Logging & Analytics System — Deep Dive Documentation¶
Generated: 2026-04-11 Scope: Backend Logger/Analytic modules + entity + Winston pipeline + Frontend dashboard pages/widgets/charts Files Analyzed: 34 (9 backend + 25 frontend) Lines of Code: ~5,800+ (backend ~1,700 + frontend ~4,100) Workflow Mode: Exhaustive Deep-Dive Verified Against: Actual route registration, middleware chain, API response shapes, user flow traces
Overview¶
The Logging & Analytics system consists of two architecturally independent subsystems:
- HTTP Logging Pipeline — Winston-based request logger with PostgreSQL transport (express-winston → Winston → PostgresTransport → Logger entity)
- Dashboard Analytics Module — REST endpoint serving aggregated business metrics (user counts, blog stats, payment summaries) consumed by a React dashboard with charting widgets
Critical Discovery: The HTTP logging pipeline is entirely disabled in the running application. The httpLogger middleware is imported but never registered via app.use(). The Logger entity, LoggerService, and PostgresTransport are dead code in practice. The only active Winston usage is a single direct logger.error() call in the invite email event handler.
Purpose: Provide admin-facing dashboard analytics and (theoretically) HTTP request logging Key Responsibilities: Business metric aggregation, time-series analytics (daily/weekly/monthly), recent activity feeds, request logging (disabled) Integration Points: Queries User, Blog, ContactMessage, Payment, GenericPage entities; Winston transports; React Query + Recharts + ApexCharts on frontend
Architecture Summary¶
BACKEND (Disabled HTTP Logging Pipeline)
=========================================
httpLogger.ts (express-winston) ─── NEVER REGISTERED via app.use()
│
└── logger.ts (Winston instance)
├── Console transport (active for direct logger calls only)
├── PostgresTransport ──► LoggerService ──► Logger entity (DEAD - never receives data)
└── DailyRotateFile (conditional, DEAD - never receives data)
BACKEND (Active Analytics Pipeline)
====================================
GET /api/v1/analytics
│
├── auth() middleware (JWT check only, NO permission)
├── contextMiddleware
└── AnalyticController
└── AnalyticService.getDashboardAnalytics()
├── getTotalCounts (raw SQL: 5 subqueries)
├── getTimeBasedAnalytics (12+ raw SQL queries)
├── getRecentBlogs/Users/Contacts/Payments (4 raw SQL queries)
└── getBlogWithAuthorStats (3 raw SQL queries)
Total: ~19-24 DB queries per API call (ZERO caching)
FRONTEND (Dashboard User Flow)
===============================
/dashboard route
│
├── middleware.js (checks cookie exists, NO JWT validation)
├── layout.js (fetches user, nav links, settings → syncs to Redux)
└── page.js → DashboardPageV3
├── PermissionWrapper("dashboard.view")
├── useDashboard() → GET /api/v1/analytics
└── Renders: WelcomeSection, 5 StatCards, TrendChart, RecentActivity, BlogByAuthor
Complete File Inventory¶
Backend Files (9 files, ~1,700 LOC)¶
entity/Logger.ts¶
Purpose: TypeORM entity for the logger table storing HTTP request log entries.
Lines of Code: 47
What Future Contributors Must Know: This entity is DEAD CODE — the HTTP logging pipeline that writes to it is disabled. The table may exist in the database from past migrations but receives no new data.
Exports:
- Logger (class, TypeORM entity)
Columns: | Column | Type | Nullable | Notes | |--------|------|----------|-------| | id | int (PK, auto) | no | | | status | int | yes | HTTP status code | | responseTime | string | no | Stored as "120ms" format — blocks numeric queries | | success | boolean | no | | | errorMessage | string | yes | | | userId | number | yes | No FK relation — plain number, no referential integrity | | ip | string | no | | | requestedAt | timestamp with tz | no | | | createdAt | timestamp | no | Auto | | updatedAt | timestamp | no | Auto — unusual for immutable log data | | deletedAt | timestamp | yes | Soft delete — unusual for logs |
Dependencies:
- typeorm — Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, DeleteDateColumn
Used By:
- LoggerService (via getDbRepository(Logger))
Key Issues:
- (Medium) No foreign key relation for userId — no referential integrity, cannot JOIN to User via TypeORM relations
- (Medium) responseTime stored as string — prevents numeric aggregation queries (AVG, MAX, percentiles)
- (Low) No indexes on any columns — queries at scale will table-scan
- (Low) updatedAt on immutable log data; soft delete on logs is unusual
- (Low) Commented-out message column (lines 27-28)
app/modules/v1/Logger/logger.service.ts¶
Purpose: Service layer that creates Logger entity records in the database. Lines of Code: 27
What Future Contributors Must Know: This service is dead code — its only consumer (PostgresTransport) never receives data because httpLogger is disabled. The ICreateLoggerPayload interface does not include path or method fields that PostgresTransport sends, so even if re-enabled, those fields would be silently dropped.
Exports:
- LoggerService — object with createLogger(payload: ICreateLoggerPayload): Promise<Logger>
Dependencies:
- Logger entity
- getDbRepository from shared/getDbRepository
Used By:
- PostgresTransport.ts only
Key Issues:
- (High) Interface omits path and method — PostgresTransport passes these but they are silently dropped (no columns in entity)
- (Medium) No error handling — errors propagate to caller
- (Low) No input validation
app/middlewares/logger.ts¶
Purpose: Creates and configures the Winston logger instance with Console, PostgresTransport, and optional DailyRotateFile transports. Lines of Code: 67
What Future Contributors Must Know: The Winston logger IS instantiated and available for direct logger.error() calls. However, it never receives HTTP request data because the httpLogger middleware is disabled. The PostgresTransport is instantiated but only writes to DB when config.production === true.
Exports:
- logger — winston.Logger instance
Dependencies:
- winston
- winston-daily-rotate-file
- PostgresTransport
Used By:
- helper/httpLogger.ts (passes to express-winston — but httpLogger is unused)
- app/events/handlers/inviteUserCreate.handler.ts (direct logger.error() call — the ONLY active consumer)
Transport Configuration:
| Transport | Condition | Status |
|-----------|-----------|--------|
| Console | Always | Active (for direct logger calls) |
| PostgresTransport | Always instantiated, writes only when config.production | Receives data only from direct logger.error() calls |
| DailyRotateFile | ENABLE_FILE_LOGS=true AND !process.env.VERCEL | Conditional |
DailyRotateFile Config: logs/%DATE%.log, YYYY-MM-DD, gzip, 20MB max, 14-day retention
Key Issues:
- (Medium) File comment says // utils/logger.ts but path is app/middlewares/logger.ts
- (Medium) Console transport always active in production — duplicate output on non-serverless deployments
- (Low) Commented-out format (lines 31-33)
- (Low) responseMeta as any cast loses type safety
helper/httpLogger.ts¶
Purpose: Express middleware using express-winston to log HTTP requests/responses via the Winston logger. Lines of Code: 43
What Future Contributors Must Know: THIS MIDDLEWARE IS NEVER REGISTERED. It is imported in app.ts but never called via app.use(). It is explicitly commented out in middleware.ts. The entire file is dead code.
Exports:
- httpLogger — express-winston middleware
Dependencies:
- express-winston
- logger from ../app/middlewares/logger
- Request, Response from express
Used By:
- app.ts (imported, never used — dead import)
- middleware.ts (imported AND used — both commented out)
Key Issues:
- (Critical) Entirely dead code — middleware never registered. HTTP request logging does not function.
- (High) req._startAt may be undefined — uses process.hrtime(req._startAt) but _startAt is set by a separate line in middleware.ts (line 69). If httpLogger were re-enabled without middleware.ts running first, it would throw.
- (Medium) req.user leaked into log meta — full user object including potentially sensitive fields
- (Medium) Comment says // middlewares/httpLogger.ts but path is helper/httpLogger.ts
- (Low) Emoji in error messages
app/transporter/PostgresTransport.ts¶
Purpose: Custom Winston transport that writes log entries to the PostgreSQL logger table via LoggerService.
Lines of Code: 50
What Future Contributors Must Know: This transport is instantiated but never receives HTTP request data because httpLogger is disabled. It may receive data from direct logger.error() calls (e.g., invite email handler) but those calls don't include the HTTP meta fields this transport expects.
Exports:
- PostgresTransport (class extending winston-transport)
Dependencies:
- winston-transport
- LoggerService
- config
Used By:
- middlewares/logger.ts (instantiated as a transport)
Key Issues:
- (Critical) path and method fields written to logData but NOT in Logger entity — data silently lost
- (High) Production-only logging gate (config.production) — Logger entity is dead in dev/staging
- (Medium) DBLogInfo interface defined but never used
- (Medium) ip extracted twice with different fallback chains — redundant code
- (Low) Uses console.error instead of separate error handling
app/modules/v1/Analytic/analytic.routes.ts¶
Purpose: Express router defining the analytics API endpoint. Lines of Code: 13
What Future Contributors Must Know: There is a single endpoint GET /api/v1/analytics (mounted via route registration in routes/v1/index.ts). It has auth() (JWT) but NO permission check. Any authenticated user can access all analytics data including user emails and payment amounts.
Exports:
- router (Express Router, default export)
Route: GET / → auth() → contextMiddleware → AnalyticController.getDashboardAnalytics
Dependencies:
- express Router
- auth middleware
- contextMiddleware
- AnalyticController
Used By:
- app/routes/v1/index.ts — mounted at /analytics
Key Issues:
- (Critical) No permission check — auth() called with no arguments, any authenticated user sees all analytics including user emails and payment amounts. No analytics.view or dashboard.view permission exists in seed data.
- (Medium) Validation schema from analytic.validation.ts is never applied as middleware
app/modules/v1/Analytic/analytic.validation.ts¶
Purpose: Zod validation schema for analytics query parameters. Lines of Code: 22
What Future Contributors Must Know: This file is 100% dead code. It defines a refresh query parameter validation that is never imported or used.
Exports:
- AnalyticValidation — object with getDashboardAnalytics Zod schema
Key Issues: - (Medium) Entirely dead code — never imported or applied as middleware
app/modules/v1/Analytic/analytic.controller.ts¶
Purpose: Express controller wrapping the AnalyticService call. Lines of Code: 24
What Future Contributors Must Know: Simple passthrough — calls service, wraps in sendResponse. No data transformation.
Exports:
- AnalyticController — object with getDashboardAnalytics method (catchAsync-wrapped)
Dependencies:
- httpStatus, catchAsync, sendResponse, AnalyticService
Key Issues: - (Low) No request parameter usage — ignores all query params
app/modules/v1/Analytic/analytic.service.ts¶
Purpose: Dashboard analytics engine — queries User, Blog, ContactMessage, Payment, GenericPage entities for counts, time-series, and recent activity data. Lines of Code: 1,472 (LARGEST file in the module)
What Future Contributors Must Know: This file has a raw SQL primary path with a full TypeORM fallback. Any schema changes must be updated in BOTH paths. It runs ~19-24 DB queries per API call with ZERO caching despite importing cache utilities. The response shape does NOT include totalGames, thisMonthGames, totalUpvotes, or widgets.upvotes — but the frontend expects all of these, causing broken UI.
Exports:
- AnalyticService (class with all static methods, default export)
Public Methods:
- getDashboardAnalytics(): Promise<{analytics, recent, widgets}> — runs 7 parallel query groups
Private Methods (30+):
- getTotalCounts(dataSource) — single raw SQL with 5 scalar subqueries
- getBlogWithAuthorStats(dataSource) — 3 queries (today/week/month)
- getTimeBasedAnalytics(dataSource) — dispatches to 4 entity-specific methods × 3 time periods = 12 raw SQL queries
- getRecentBlogs/Users/Contacts/Payments(dataSource) — 4 queries, LIMIT 10
- get*WithFallback(dataSource) — 5 try/catch wrappers that fall back to TypeORM
- get*TypeORM() — complete TypeORM reimplementation of every query
- getEmptyTimeBasedAnalytics(), getWeeksInMonth() — utilities
- getFallbackAnalytics() — complete TypeORM fallback for entire dashboard
Dependencies:
- Entities: Blog, User, GenericPage, ContactMessage, Payment
- getDbRepository, getDataSource (shared)
- getCache, addCache (shared — IMPORTED BUT NEVER USED)
- platform from node:os (IMPORTED BUT NEVER USED)
- transformImageUrl (helper — IMPORTED BUT NEVER USED)
Key Issues:
- (Critical) No caching despite importing getCache/addCache — ~19-24 DB queries per API call. Under load this hammers the database.
- (Critical) 3 unused imports: platform (node:os), transformImageUrl, getCache/addCache
- (High) Massive code duplication — ~800+ lines of near-identical query patterns (monthly/daily/weekly × 4 entities × 2 implementations)
- (High) TypeORM fallback fires ~96 individual queries (12 months + 7 days + ~5 weeks × 4 entities)
- (High) Inconsistent LIMIT: raw SQL returns 10 items, TypeORM fallback returns 5 for blogs/users
- (High) User emails and payment amounts exposed without permission check
- (Medium) GenericPage count queried but discarded from response
- (Medium) Response shape differs between primary and fallback paths (total extra key)
- (Medium) 3 identical SQL queries in blogWithAuthor stats (only date parameter differs)
- (Medium) andWhere without preceding where in TypeORM user analytics
- (Low) console.error used instead of Winston logger
- (Low) Blog/User fallback response shape differs from raw SQL (extra fields)
Frontend Files (25 files, ~4,100 LOC)¶
api/dashboard/index.js¶
Purpose: React Query hook to fetch dashboard analytics from GET /api/v1/analytics.
Lines of Code: 18
What Future Contributors Must Know: The catch block swallows errors — isError from React Query will never be true. All error UI in consuming components is dead code. An identical duplicate exists at hooks/useDashboardData.js.
Exports:
- useDashboard (named)
Configuration: queryKey ["dashboard"], staleTime 5min, refetchOnWindowFocus disabled
Key Issues:
- (High) Error swallowed — catch logs but does not re-throw, query resolves with undefined
- (Medium) Duplicate implementation at hooks/useDashboardData.js (byte-for-byte identical)
- (Low) console.error in production
Used By:
- dashboard-page-v3.jsx (active)
hooks/useDashboardData.js (DUPLICATE)¶
Purpose: Byte-for-byte identical duplicate of api/dashboard/index.js.
Lines of Code: 18
Key Issues: - (Medium) 100% duplicate — should be deleted
Used By:
- dashboard-page-v2.jsx (dead code)
components/pages/dashboard/dashboard-page-v3.jsx (ACTIVE — renders at /dashboard)¶
Purpose: Production dashboard page with widget-based stat cards and trend charts. Lines of Code: 124
What Future Contributors Must Know: This is the ONLY dashboard page that is rendered. V1 and V2 are dead code. The component wraps in PermissionWrapper with permission={["dashboard.view"]}. It imports TopGamesUpvotes from blog-by-author but never renders it — only BlogByAuthor is used.
Exports:
- DashboardPageV3 (default)
Hooks: useDashboard() from @/api/dashboard
Key Issues:
- (Critical) Reads dashboardData.analytics.totalUpvotes and dashboardData.widgets.upvotes — these keys DO NOT EXIST in the backend response. UpvotesStatCard always shows 0/empty.
- (High) Error UI unreachable — useDashboard swallows errors, isError never true
- (High) TopGamesUpvotes imported but never rendered — dead import, gaming template leftover
- (Medium) "Games" terminology in WelcomeSection — domain mismatch
components/pages/dashboard/dashboard-page-v2.jsx (DEAD CODE)¶
Purpose: Second iteration dashboard. Lines of Code: 86 Status: DEAD CODE — zero imports across codebase. Not rendered by any route.
components/pages/dashboard/dashboard-page.jsx (DEAD CODE)¶
Purpose: Original dashboard with 100% hardcoded dummy data. Lines of Code: 80 Status: DEAD CODE — zero imports across codebase.
components/pages/dashboard/welcome-section.jsx¶
Purpose: Welcome banner showing user name/avatar and statistics. Lines of Code: 68
What Future Contributors Must Know: Shows "Total Games" and "This Month" labels but these are ghost metrics from a gaming template. Backend returns no totalGames or thisMonthGames — values are always 0.
Key Issues:
- (Critical) Reads analytics.totalGames and analytics.thisMonthGames — DO NOT EXIST in backend response. Always displays 0.
- (High) "Total Games" label — SaaS boilerplate, not a gaming platform
- (Medium) Missing "use client" directive — works only because parent has it
- (Medium) Mixed state sources — Redux for user, React Query for stats
components/pages/dashboard/widgets/stat-card.jsx¶
Purpose: Central reusable stat card — renders heading, total count, percentage change, timeline selector, and chart. Supports area, line, horizontal-bar, and custom-bar chart types. Lines of Code: 416
What Future Contributors Must Know: This is the composition base for domain-specific stat cards (contacts, payments, users, upvotes). It uses ApexCharts (dynamically imported, SSR-disabled). The calculateAnalytics() compares data[0] vs data[1] which assumes newest-first ordering.
Chart Library: react-apexcharts (dynamic import)
Key Issues:
- (Medium) monthMap object duplicated 3 times within the file
- (Medium) calculateAnalytics() compares index [0] vs [1] — wrong if data is chronological order
- (Low) Naive deepMerge doesn't handle arrays
- (Low) Comment references "games-stat-card style" — gaming template leftover
components/pages/dashboard/widgets/blogs-stat-card.jsx¶
Purpose: Blog stat card with custom CSS bar chart. Lines of Code: 150
Key Issues:
- (High) Uses Gamepad2 (gamepad) icon — should be a blog/article icon
- (High) Duplicates ~150 LOC of StatCard logic instead of composing <StatCard chartType="custom-bar" />
- (Medium) Same calculateAnalytics() index direction issue
components/pages/dashboard/widgets/contacts-stat-card.jsx¶
Purpose: Thin wrapper around StatCard for contacts. Lines of Code: 20 Pattern: CORRECT — delegates to StatCard via props.
Key Issues:
- (Low) Uses FileText icon — MessageSquare would be more semantic
components/pages/dashboard/widgets/payments-stat-card.jsx¶
Purpose: Thin wrapper around StatCard for payments. Lines of Code: 20 Pattern: CORRECT composition pattern.
Key Issues:
- (Medium) Uses MessageSquare icon (chat bubble) for payments — icons are SWAPPED with contacts-stat-card
components/pages/dashboard/widgets/users-stat-card.jsx¶
Purpose: Thin wrapper around StatCard for users with line chart. Lines of Code: 48 Pattern: CORRECT with custom chart options.
Key Issues: - (Low) Hardcoded colors instead of CSS variables
components/pages/dashboard/widgets/upvotes-stat-card.jsx¶
Purpose: Thin wrapper for "Website Interactions" (upvotes) stat card. Lines of Code: 93
What Future Contributors Must Know: This widget receives undefined for both data and totalCount because the backend does not return widgets.upvotes or analytics.totalUpvotes. It always renders empty / 0.
Key Issues: - (Critical) Receives undefined data — backend has no upvotes endpoint. Widget is a ghost. - (Low) Named "upvotes" but heading says "Website Interactions"
components/pages/dashboard/widgets/trend-chart.jsx¶
Purpose: Grouped bar chart comparing Contacts, Users, Blogs over selectable timeline using Recharts. Lines of Code: 130
Key Issues:
- (Medium) ResponsiveContainer imported but never used
- (Medium) Merges data by array index, not key — misaligned if arrays differ in length/order
- (Low) No empty-state UI
components/pages/dashboard/widgets/blog-by-author.jsx¶
Purpose: Top 10 blogs by author in a custom CSS gradient bar chart with ranked badges. Lines of Code: 159
Key Issues:
- (High) "Today" filter broken — backend returns blogWithAuthor.today but frontend uses data?.["day"] for the "Today" timeline selector value. Key mismatch causes "No data available".
- (Medium) Variable named topGames — should be topAuthors
- (Medium) .sort() mutates array in-place — should spread first
- (Low) Timeline labels inconsistent with other widgets
components/pages/dashboard/widgets/recent-activity.jsx¶
Purpose: Unified activity feed aggregating recent blogs, contacts, users, payments sorted by time. Lines of Code: 205
Key Issues:
- (Medium) Gamepad2 imported but never used — dead import
- (Medium) CSS class typo: col-span-ful should be col-span-full — layout broken
- (Low) Payment title template literal with || "NA" fallback doesn't work as intended
components/pages/dashboard/charts.jsx (DEAD CODE — V1 only)¶
Purpose: Three-column chart section with Revenue Updates and Sales Overview. Lines of Code: 568 Status: DEAD CODE — only used by V1 which is dead.
Key Issues: - (High) 568 LOC dead code; 6 Recharts imports unused
components/pages/dashboard/charts-v2.jsx (DEAD CODE — V2 only)¶
Purpose: Data-driven chart section for V2 dashboard. Lines of Code: 304 Status: DEAD CODE — only used by V2 which is dead.
Key Issues:
- (High) Double parseInt produces NaN for undefined values
components/pages/dashboard/weekly-stats.jsx (DEAD CODE)¶
Lines of Code: 78. Only used by V1. All hardcoded stats.
components/pages/dashboard/payment-gateways.jsx (DEAD CODE)¶
Lines of Code: 79. Only used by V1. 100% hardcoded. Button does nothing.
components/pages/dashboard/product-performance.jsx (DEAD CODE)¶
Lines of Code: 217. Not imported by ANY dashboard version. Completely orphaned.
components/pages/dashboard/expense-pi-chart.jsx (DEAD CODE)¶
Lines of Code: 82. Only used by V1. Filename typo: "pi" should be "pie".
components/pages/dashboard/sales-bar-chart.jsx¶
Lines of Code: 53
Key Issues:
- (Critical) Props destructuring is broken: (data=[], totalSales=0) instead of ({data=[], totalSales=0}). Receives entire props object as first param. Chart renders nothing. Not used by V3 (dead in practice).
components/pages/dashboard/recent-transactions.jsx¶
Lines of Code: 75
Key Issues: - (Critical) 100% hardcoded dummy data — no props, no API. Fake names, amounts, times. Not used by V3.
components/pages/dashboard/recent-users-table.jsx¶
Purpose: Recent users data table with avatar, name, email, role, date. Lines of Code: 102
Key Issues:
- (Low) FileText icon for users card — should be Users
- (Low) Commented-out Actions column
components/pages/dashboard/recent-blogs-table.jsx¶
Purpose: Recent blogs data table with thumbnail, title, excerpt, author. Lines of Code: 133
Key Issues:
- (Medium) Badge and Avatar/AvatarFallback imported but never used — dead imports
- (Low) Uses date-fns for dates while other components use getReadableDate — inconsistent
components/pages/dashboard/yearly-sales.jsx (DEAD CODE — V1)¶
Lines of Code: 53. Summary values hardcoded ($36,358 / $5,296).
components/pages/dashboard/yearly-sales-v2.jsx¶
Lines of Code: 76
Key Issues:
- (High) averageExpenses fabricated as totalSales * 0.15 — dead code (declared, never rendered)
- (Medium) h-68 is NOT a valid Tailwind class — chart container may collapse to 0 height
- (Medium) Hardcoded fallback data shown without user indication
Contributor Checklist¶
Risks & Gotchas¶
- The entire HTTP logging pipeline is disabled — re-enabling requires registering
httpLoggerinapp.tsor un-commenting inmiddleware.ts, AND ensuring_startAtis set onreq - The Logger entity is missing
pathandmethodcolumns — re-enabling logging will silently lose this data - Analytics endpoint has NO caching and NO permission check — any authenticated user triggers ~20 DB queries
- Backend response shape does NOT match frontend expectations for
totalGames,thisMonthGames,totalUpvotes,widgets.upvotes— 3 widgets permanently broken blogWithAuthorusestodaykey but frontend readsday— "Today" filter always empty- Two charting libraries bundled (ApexCharts + Recharts) — significant bundle size impact
- V1 and V2 dashboard components + their exclusive dependencies are ~1,500 LOC of dead code
Pre-change Verification Steps¶
- Check if
httpLoggeris registered inapp.tsormiddleware.tsbefore assuming logging works - Verify Logger entity columns match PostgresTransport's logData shape
- Compare
analytic.service.tsresponse keys against V3's prop access patterns - Check both raw SQL AND TypeORM fallback paths when changing queries
- Verify
dashboard.viewpermission is seeded and assigned
Suggested Tests Before PR¶
- Backend: Test analytics endpoint returns correct shape; test with no data; test query performance
- Backend: Test Logger entity creation (if re-enabling logging)
- Frontend: Test
useDashboarderror propagation (currently broken) - Frontend: Test each widget with
undefined/null/empty data - Frontend: Test BlogByAuthor "Today" filter against backend
todaykey - Integration: Verify response shape from
GET /api/v1/analyticsmatches V3 expectations
Data Flow¶
Dashboard Analytics Flow (Active)¶
User visits /dashboard
│
├── Next.js middleware: checks "token" cookie exists (no JWT validation)
│
├── Dashboard layout: fetches user, nav links, settings
│
└── DashboardPageV3: PermissionWrapper("dashboard.view")
│
└── useDashboard() hook
│
└── GET /api/v1/analytics (Axios via axiosInstance)
│
├── Backend: auth() → contextMiddleware → AnalyticController
│
└── AnalyticService.getDashboardAnalytics()
│
├── Promise.all([
│ getTotalCountsWithFallback(), // 1 query (5 subqueries)
│ getTimeBasedAnalytics(), // 12+ queries
│ getRecentBlogsWithFallback(), // 1 query
│ getRecentUsersWithFallback(), // 1 query
│ getRecentContactsWithFallback(), // 1 query
│ getRecentPaymentsWithFallback(), // 1 query
│ getBlogWithAuthorStats() // 3 queries
│ ])
│
└── Returns: { analytics, recent, widgets }
HTTP Logging Flow (Disabled)¶
HTTP Request arrives
│
├── middleware.ts: _startAt set on req (line 69)
│
├── httpLogger (express-winston): DISABLED — commented out in middleware.ts
│ imported but unused in app.ts
│
└── [If were enabled]:
httpLogger → Winston logger → PostgresTransport
│
├── config.production check
└── LoggerService.createLogger()
└── Logger entity INSERT
Data Entry Points¶
- Backend: Single entry:
GET /api/v1/analytics - Frontend: Single entry:
useDashboard()hook
Data Exit Points¶
- Backend → Frontend: JSON response with
{ analytics, recent, widgets } - Backend → DB (disabled): Logger entity INSERT via PostgresTransport
Integration Points¶
APIs Exposed¶
GET /api/v1/analytics— Dashboard analytics data- Auth: JWT required (any role)
- Permission: NONE (should require
analytics.view) - Response:
{ analytics: {totalUsers, totalBlogs, totalContacts, totalPayments}, recent: {...}, widgets: {...} }
Shared State¶
- Redux
auth.user— WelcomeSection reads user name/avatar - React Query
["dashboard"]— Dashboard data shared via queryKey (5min stale time)
Database Access¶
| Table | Operation | Query Type |
|---|---|---|
| user | COUNT, SELECT (recent 10) | Raw SQL + TypeORM fallback |
| blogs | COUNT, SELECT (recent 10), GROUP BY author | Raw SQL + TypeORM fallback |
| contact_messages | COUNT, SELECT (recent 10) | Raw SQL + TypeORM fallback |
| payment | COUNT, SELECT (recent 10), SUM(amount) | Raw SQL + TypeORM fallback |
| generic_pages | COUNT | Raw SQL only (result discarded) |
| logger | NONE — never queried by analytics | N/A |
Dependency Graph¶
Entry Points (not imported by others in scope)¶
app/(dashboard-layout)/dashboard/page.js— route entryapp/routes/v1/index.ts— mounts analytics routeapp/middlewares/middleware.ts— middleware registration (httpLogger commented out)
Leaf Nodes (don't import others in scope)¶
entity/Logger.tsanalytic.validation.ts(dead code)widgets/stat-card.jsx- All thin stat card wrappers
Circular Dependencies¶
✓ No circular dependencies detected
Testing Analysis¶
Test Coverage Summary¶
- Statements: 0%
- Branches: 0%
- Functions: 0%
- Lines: 0%
Test Files¶
None. Zero test files exist for any backend or frontend file in this deep-dive scope.
Testing Gaps¶
- No unit tests for AnalyticService query correctness
- No integration tests for analytics API endpoint
- No tests for Logger entity creation
- No tests for PostgresTransport behavior
- No component tests for any dashboard widget
- No snapshot tests for dashboard page versions
- No tests for useDashboard error handling
- No tests for frontend-backend response shape compatibility
Dead Code Summary¶
Backend Dead Code (~182 LOC)¶
| File | LOC | Reason |
|---|---|---|
| helper/httpLogger.ts | 43 | Middleware never registered |
| analytic.validation.ts | 22 | Never imported/applied |
| Logger entity (effective) | 47 | Never receives data (httpLogger disabled) |
| LoggerService (effective) | 27 | Only consumer is disabled pipeline |
| PostgresTransport (effective) | 50 | Only receives direct logger.error() calls, not HTTP data |
| Subtotal | ~182 |
Frontend Dead Code (~2,163 LOC)¶
| File | LOC | Reason |
|---|---|---|
| dashboard-page.jsx (V1) | 80 | Zero imports — dead |
| dashboard-page-v2.jsx (V2) | 86 | Zero imports — dead |
| charts.jsx (V1) | 568 | Only V1 consumer — dead |
| charts-v2.jsx (V2) | 304 | Only V2 consumer — dead |
| weekly-stats.jsx | 78 | Only V1 consumer — dead |
| payment-gateways.jsx | 79 | Only V1 consumer — dead |
| product-performance.jsx | 217 | Zero imports — orphaned |
| expense-pi-chart.jsx | 82 | Only V1 consumer — dead |
| sales-bar-chart.jsx | 53 | Not used by V3, broken props |
| recent-transactions.jsx | 75 | 100% hardcoded, not used by V3 |
| yearly-sales.jsx | 53 | V1 with hardcoded summaries |
| hooks/useDashboardData.js | 18 | Byte-for-byte duplicate of api/dashboard/index.js |
| TopGamesUpvotes import (V3 line 7) | — | Imported, never rendered |
| Subtotal | ~2,163 |
Total removable dead code: ~2,345 LOC
Consolidated Known Issues¶
Critical (9 issues)¶
| # | File | Issue |
|---|---|---|
| C1 | httpLogger.ts | Entire HTTP logging pipeline is dead — middleware never registered, Logger entity never receives data |
| C2 | analytic.routes.ts | No permission check — any authenticated user sees all analytics (emails, payment amounts) |
| C3 | analytic.service.ts | No caching — ~19-24 DB queries per call, imports cache utils but never uses them |
| C4 | analytic.service.ts | 3 unused imports — platform, transformImageUrl, getCache/addCache |
| C5 | PostgresTransport.ts | path/method not in Logger entity — data silently lost if pipeline re-enabled |
| C6 | dashboard-page-v3.jsx | totalUpvotes/widgets.upvotes don't exist in backend — UpvotesStatCard permanently broken |
| C7 | welcome-section.jsx | totalGames/thisMonthGames don't exist in backend — always shows 0 |
| C8 | sales-bar-chart.jsx | Props destructuring broken — (data, totalSales) not ({data, totalSales}) — renders nothing |
| C9 | recent-transactions.jsx | 100% hardcoded dummy data — no props, no API, fake names/amounts |
High (14 issues)¶
| # | File | Issue |
|---|---|---|
| H1 | api/dashboard/index.js | Error swallowed — React Query isError never true, all error UI unreachable |
| H2 | analytic.service.ts | ~800+ LOC of duplicated query patterns (raw SQL + TypeORM × 4 entities) |
| H3 | analytic.service.ts | TypeORM fallback fires ~96 individual queries |
| H4 | analytic.service.ts | Inconsistent LIMIT (10 vs 5) between raw SQL and TypeORM fallback |
| H5 | analytic.service.ts | User emails + payment amounts exposed without authorization |
| H6 | httpLogger.ts | req._startAt may be undefined — throws if re-enabled without morgan |
| H7 | logger.service.ts | Interface omits path/method — PostgresTransport sends them, silently dropped |
| H8 | blog-by-author.jsx | "Today" filter broken — backend returns today key, frontend reads day |
| H9 | blogs-stat-card.jsx | Uses Gamepad2 icon; duplicates 150 LOC of StatCard logic |
| H10 | dashboard-page-v3.jsx | Error UI unreachable due to H1 |
| H11 | yearly-sales-v2.jsx | Fabricated averageExpenses = totalSales * 0.15 (dead code) |
| H12-H16 | V1/V2 files | 5 files totaling ~1,100 LOC confirmed dead code |
Medium (23 issues)¶
| # | File | Issue |
|---|---|---|
| M1 | Logger.ts | No FK on userId; responseTime stored as string |
| M2 | logger.ts | Comment says wrong path; console transport in production |
| M3 | httpLogger.ts | req.user leaked into log meta |
| M4 | PostgresTransport.ts | DBLogInfo interface unused; ip extracted twice |
| M5 | analytic.service.ts | GenericPage count queried but discarded; response shape differs in fallback |
| M6 | analytic.validation.ts | Entirely dead code |
| M7 | hooks/useDashboardData.js | Byte-for-byte duplicate |
| M8 | stat-card.jsx | monthMap duplicated 3×; calculateAnalytics direction issue |
| M9 | payments-stat-card.jsx | MessageSquare icon for payments (swapped with contacts) |
| M10 | trend-chart.jsx | Unused ResponsiveContainer; index-based data merge fragile |
| M11 | blog-by-author.jsx | topGames variable name; .sort() mutates array |
| M12 | recent-activity.jsx | Gamepad2 dead import; col-span-ful typo breaks layout |
| M13 | recent-blogs-table.jsx | Badge, Avatar, AvatarFallback imported but unused |
| M14 | yearly-sales-v2.jsx | h-68 invalid Tailwind class; hardcoded fallback |
| M15 | welcome-section.jsx | Missing "use client"; mixed Redux + React Query state |
| M16-M23 | Various | Additional medium-severity items (icon mismatches, hardcoded data, etc.) |
Low (18 issues)¶
Logger entity indexes, soft delete, updatedAt; Console log statements in production; Hardcoded colors; Inconsistent date formatting; Missing tooltips/Y-axis; Commented-out features; Gaming template leftovers in comments/variable names; Minor typos ("pi" → "pie", "Minecraf", "Expance", "absolute sure").
TOTAL: 64 issues (9 Critical, 14 High, 23 Medium, 18 Low)
Icon Swap Summary¶
| Component | Current Icon | Correct Icon | Issue |
|---|---|---|---|
| blogs-stat-card | Gamepad2 (gamepad) |
FileText or Newspaper |
Gaming template leftover |
| contacts-stat-card | FileText |
MessageSquare |
Swapped with payments |
| payments-stat-card | MessageSquare |
DollarSign or CreditCard |
Swapped with contacts |
| recent-activity | Gamepad2 imported |
Remove (unused) | Dead import |
Chart Library Analysis¶
Two chart libraries are bundled in the dashboard:
| Library | Used By | Bundle Impact |
|---|---|---|
| react-apexcharts | stat-card.jsx (+ all thin wrappers) | ~500KB uncompressed |
| recharts | trend-chart.jsx, yearly-sales*.jsx | ~300KB uncompressed |
| Custom CSS bars | blogs-stat-card.jsx, blog-by-author.jsx, stat-card.jsx (custom-bar) | 0 |
If V1/V2 dead code is removed, Recharts is only used by 2 active components (TrendChart, YearlySalesV2). Consider consolidating to a single library.
Related Code & Reuse Opportunities¶
Dashboard Skeletons¶
components/ui/dashboard-skeletons.jsx exists but is never imported by any dashboard page — potential for loading states.
Analytics Route Stub¶
app/(dashboard-layout)/dashboard/analytics/page.js renders <div>Overview Page</div> — placeholder for a dedicated analytics page that was never built.
StatCard Composition Pattern¶
4 of 5 domain stat cards correctly compose StatCard via thin wrappers. BlogsStatCard should be refactored to match (replace 150 LOC with ~20 LOC wrapper).
Shared Customization System¶
The dashboard/customization/ folder (5 files, ~1,938 LOC) is NOT part of analytics — it's a generic CRUD manager used by blog categories, tags, product categories, etc. Previously miscategorized.
Modification Guidance¶
To Re-enable HTTP Logging¶
- Un-comment
app.use(httpLogger)inmiddleware.ts(line 65) or add toapp.ts - Add
path(varchar) andmethod(varchar) columns to Logger entity - Update
ICreateLoggerPayloadin LoggerService to includepathandmethod - Add indexes on
requestedAt,userId,status,ip,path - Change
responseTimecolumn type from string to numeric - Verify
_startAtis attached toreqbefore httpLogger runs
To Fix Dashboard Data Mismatches¶
- Either add
totalUpvotes,totalGames,thisMonthGames,widgets.upvotesto the backend response, OR remove the frontend components that reference them - Fix BlogByAuthor timeline key: change backend
todaytoday, or change frontendvalue="day"tovalue="today" - Replace "Total Games" / "This Month" labels with actual SaaS metrics
To Clean Up Dead Code¶
- Delete V1/V2 dashboard pages and their exclusive dependencies (~2,163 LOC)
- Delete
hooks/useDashboardData.js(duplicate) - Remove unused imports in
analytic.service.ts - Consider deleting
analytic.validation.ts(dead code)
To Add Caching¶
- Use the already-imported
getCache/addCachefromshared/cache - Cache the entire dashboard response with a 1-5 minute TTL
- Consider per-query caching for the most expensive time-series queries
Testing Checklist for Changes¶
- Analytics API returns correct shape matching frontend expectations
- Permission check blocks non-admin users
- useDashboard properly propagates errors
- Each widget renders correctly with valid, empty, and undefined data
- BlogByAuthor "Today" filter returns data
- UpvotesStatCard either works or is removed
- WelcomeSection shows meaningful metrics (not "Total Games")
- Logger entity columns match PostgresTransport logData (if re-enabling)
- No user emails or payment data exposed to unauthorized users
Generated by document-project workflow (deep-dive mode)
Base Documentation: docs/index.md
Scan Date: 2026-04-11
Analysis Mode: Exhaustive
Verified: Route traces, middleware chain, API response shapes, user flows all validated against actual code