diff --git a/SECURITY_AUDIT_REPORT.md b/SECURITY_AUDIT_REPORT.md new file mode 100644 index 00000000..0401a59c --- /dev/null +++ b/SECURITY_AUDIT_REPORT.md @@ -0,0 +1,530 @@ +# Comprehensive API Security & Code Quality Audit Report + +**Audit Date:** 2026-04-01 +**Scope:** All 291 API route handlers under `/workspace/src/app/api/` +**Auditor:** Automated code review + +--- + +## Executive Summary + +The codebase has a **strong security foundation** with centralized middleware (`apiHandler`), a well-designed permission system, multi-tenant isolation patterns, and Zod validation across most endpoints. However, several **critical and high-severity issues** were identified — primarily around unauthenticated admin endpoints, public-facing IDOR vulnerabilities, and inconsistent enforcement of multi-tenant isolation. + +### Severity Distribution + +| Severity | Count | Description | +|----------|-------|-------------| +| **CRITICAL** | 5 | Immediate exploitation risk; data breach or privilege escalation | +| **HIGH** | 8 | Significant security impact requiring prompt remediation | +| **MEDIUM** | 10 | Defense-in-depth gaps or inconsistency issues | +| **LOW** | 6 | Code quality, hardening, or best-practice deviations | + +--- + +## Shared Infrastructure Assessment + +### `apiHandler` Middleware (`src/lib/api-middleware.ts`) + +**Strengths:** +- Centralized auth, permission, CSRF, content-type, and body-size validation +- CSRF enforcement on state-changing methods (POST, PUT, PATCH, DELETE) +- Bearer token fallback for API clients +- 1MB body size limit +- Content-Type enforcement for POST/PUT/PATCH + +**Weaknesses:** +- DELETE method is not listed in the Content-Type check (`['POST', 'PUT', 'PATCH']` at line 461), so DELETE requests bypass Content-Type validation — acceptable for parameterless deletes but inconsistent +- `skipCsrf` option exists but isn't documented for webhook routes that legitimately need it +- No global rate limiting at the middleware level; rate limiting is applied per-route + +### `auth-helpers.ts` — Permission System + +**Strengths:** +- Role-priority sorting, `hasStoreAccess` with org-level fallback +- Audit logging of permission checks +- Super admin bypass with explicit `'*'` permission + +**Weaknesses:** +- `getUserContext()` makes 3 sequential DB queries per call (user, memberships, storeStaff) — N+1 risk on hot paths where `apiHandler` already fetched session + +--- + +## Route-by-Route Findings + +--- + +### 1. `/api/auth/` — Authentication Routes + +#### `/api/auth/[...nextauth]/route.ts` +- **Methods:** GET, POST +- **Auth:** Handled by NextAuth +- **Severity:** No issues — standard NextAuth handler + +#### `/api/auth/signup/route.ts` +- **Methods:** POST (via `apiHandler({ skipAuth: true })`) +- **Auth:** Explicitly skipped (public endpoint) +- **Validation:** Zod schema with strong password policy (12+ chars, uppercase, lowercase, number, special) +- **Rate Limiting:** Yes — `authRateLimit` applied + +| # | Severity | Finding | +|---|----------|---------| +| 1 | **LOW** | Bcrypt cost factor is 10 (line 87). OWASP recommends 12+ for 2026 hardware. | +| 2 | **LOW** | Common password blocklist (line 34) only has 4 entries. Consider using a comprehensive list (e.g., `zxcvbn` or top-10000 list). | +| 3 | **MEDIUM** | Dev mode returns verification URL in response body (line 143). The `NODE_ENV` check is correct, but if misconfigured in staging this leaks the token. | + +#### `/api/auth/verify-email/route.ts` +- **Methods:** GET (no auth — token-based verification) +- **Auth:** Token-based +- **Validation:** SHA-256 token hashing, expiry check + +| # | Severity | Finding | +|---|----------|---------| +| 4 | **MEDIUM** | No rate limiting on the verification endpoint. An attacker could brute-force token hashes by hitting `/api/auth/verify-email?token=` at high volume. The 32-byte token space makes this impractical, but rate limiting is still best practice. | +| 5 | **LOW** | Account creation (lines 41-54) sets `accountStatus: 'APPROVED'` immediately. If the business model requires admin approval, this bypasses it for email-verified users. | + +--- + +### 2. `/api/orders/` — Order Management + +#### `/api/orders/route.ts` +- **Methods:** GET, POST +- **Auth:** Session + permission check (`orders:read`, `orders:create`) +- **Multi-tenancy:** `storeId` required and `hasStoreAccess()` verified +- **Validation:** Zod schemas for both query and create + +| # | Severity | Finding | +|---|----------|---------| +| 6 | **MEDIUM** | POST reads `storeId` from the `x-store-id` header (line 159) instead of deriving it from session. While it verifies store membership afterward (lines 167-176), the client controls which store to act on. If the membership check has a race condition or caching issue, this could allow cross-store order creation. Recommend deriving from session. | +| 7 | **LOW** | Excessive `console.log` statements with payment details (lines 200-205, 231) in production code — logs customer emails, store IDs, amounts. | + +#### `/api/orders/[id]/route.ts` +- **Methods:** GET, PATCH, DELETE +- **Auth:** Session + permissions + +| # | Severity | Finding | +|---|----------|---------| +| 8 | **HIGH** | **IDOR on unauthenticated GET:** Lines 68-98 allow unauthenticated users to fetch full order details by providing just an email or phone number in query params. There is no rate limiting and the email/phone verification is a simple string match — an attacker who knows an email can enumerate all their orders by iterating order IDs. The `storeId` parameter is also optional for unauth path (line 80 uses empty string fallback). | +| 9 | **MEDIUM** | PATCH accepts `storeId` from request body (line 151) — client-controlled tenant selection. Same pattern as finding #6. | +| 10 | **MEDIUM** | PATCH logs full request body to console (line 148) including potential PII. | + +#### `/api/orders/bulk/route.ts` +- **Methods:** PATCH +- **Auth:** Session + `getAuthorizedStoreId()` +- **Validation:** Zod with max 100 order IDs + +| # | Severity | Finding | +|---|----------|---------| +| 11 | **MEDIUM** | No explicit permission check (e.g., `orders:manage`). The doc comment claims `orders:manage` is required, but the code only checks auth + store access. Any authenticated user with store access can bulk-update orders. | + +#### `/api/orders/[id]/refund/route.ts` +- **Methods:** POST (via `apiHandler({ permission: 'orders:update' })`) +- **Auth:** Permission + store access +- **Validation:** Zod schema +- No issues — well-implemented. + +#### `/api/orders/[id]/status/route.ts` and `/api/orders/[id]/cancel/route.ts` +- Both use `apiHandler` with `orders:update` permission +- Both verify `hasStoreAccess` +- Both have Zod validation +- No issues — well-implemented. + +--- + +### 3. `/api/products/` — Product Management + +#### `/api/products/route.ts` +- **Methods:** GET, POST +- **Auth:** `apiHandler` with `products:read` / `products:create` +- **Multi-tenancy:** GET uses `requireStore: true`; POST uses `resolveTenantContext` + +| # | Severity | Finding | +|---|----------|---------| +| 12 | **HIGH** | **Mass Assignment on POST:** The entire `body` object is passed directly to `productService.createProduct(storeId, body)` (line 77) without a whitelist. If `createProduct` spreads body into a Prisma `create`, any field (e.g., `storeId`, `id`, `deletedAt`, `createdAt`) could be overwritten. The `resolveTenantContext` only validates `storeId` ownership — it doesn't strip extraneous fields. | + +#### `/api/products/[id]/route.ts` +- **Methods:** GET, PATCH, PUT, DELETE +- **Auth:** All use `apiHandler` with correct permissions +- **Multi-tenancy:** All verify `storeAccess` + +| # | Severity | Finding | +|---|----------|---------| +| 13 | **HIGH** | **Mass Assignment on PATCH and PUT:** Both pass the entire `body` to `productService.updateProduct(id, storeId, body)` (lines 75-79, 146-149) without filtering. An attacker could modify `storeId`, `id`, `createdAt`, or any protected field. | + +#### `/api/products/bulk/route.ts` +- **Methods:** POST +- **Auth:** Manual session check + `getAuthorizedStoreId` +- **Validation:** Zod schema via `createProductSchema` +- Properly validated — no mass assignment risk since each product goes through the schema. + +#### `/api/products/import/route.ts` +- **Methods:** POST (via `apiHandler({ permission: 'products:create' })`) +- **Auth:** Permission + store access +- **Validation:** Zod with `.passthrough()` on CSV records + +| # | Severity | Finding | +|---|----------|---------| +| 14 | **MEDIUM** | CSV schema uses `.passthrough()` (line 30), allowing arbitrary additional columns to flow into `bulkImport`. If the import service doesn't filter these, extra fields could reach Prisma queries. | + +--- + +### 4. `/api/payments/` — Payment Processing + +#### `/api/payments/configurations/route.ts` +- **Methods:** GET, POST +- **Auth:** Session only (no permission check) + +| # | Severity | Finding | +|---|----------|---------| +| 15 | **HIGH** | **Missing Authorization on POST:** Any authenticated user can create/update payment gateway configurations for their organization. No role check (OWNER/ADMIN) is enforced — a CUSTOMER_SUPPORT staff member could modify payment gateway credentials. | +| 16 | **HIGH** | **Missing Input Validation:** POST accepts `config` as arbitrary JSON from the body (line 60) with no Zod validation. The `gateway` is manually validated against a list, but `config` (containing API keys) has no schema validation. | + +#### `/api/payments/configurations/toggle/route.ts` +- **Methods:** POST +- **Auth:** Session + explicit OWNER/ADMIN role check on membership +- Properly secured — good role check implementation. + +#### `/api/payments/sslcommerz/initiate/route.ts` +- **Methods:** POST +- **Auth:** Session check + +| # | Severity | Finding | +|---|----------|---------| +| 17 | **HIGH** | **Missing Store Access Verification:** The `organizationId` and `storeId` are taken directly from the request body (line 32) with no verification that the authenticated user belongs to that organization/store. An attacker could initiate payments against any store by providing arbitrary `organizationId` and `storeId` values. | +| 18 | **MEDIUM** | No Zod schema — manual `if (!orderId || !amount ...)` validation misses type coercion, field length limits, and format validation. | + +#### `/api/payments/bkash/callback/route.ts` and `/api/payments/nagad/callback/route.ts` +- **Methods:** GET (callback handlers, no auth — expected) +- **Validation:** bKash validates amount and currency; Nagad does not + +| # | Severity | Finding | +|---|----------|---------| +| 19 | **HIGH** | **Nagad callback lacks amount verification:** Unlike bKash (which validates `providerAmount` vs `expectedAmount` at line 144), the Nagad callback (line 68) calls `verifyPayment` but never verifies the amount matches the order total. A manipulated Nagad callback could confirm payment for an incorrect amount. | +| 20 | **MEDIUM** | **Nagad config query is not tenant-scoped:** Line 31-35 queries `paymentConfiguration` with `gateway: 'NAGAD', isActive: true` but no `organizationId` filter. In multi-tenant deployment, this could return another store's Nagad credentials. Compare with bKash (line 81-90) which correctly scopes by `organizationId`. | + +#### `/api/payments/transactions/route.ts` +- **Methods:** GET +- **Auth:** Session + implicit store filtering via OWNER/ADMIN membership +- **Validation:** Manual query param parsing (no Zod) + +| # | Severity | Finding | +|---|----------|---------| +| 21 | **MEDIUM** | `limit` parameter (line 21) is parsed with `parseInt` with no upper bound. Setting `limit=100000` could cause memory issues. | + +--- + +### 5. `/api/webhooks/` and `/api/webhook/` — Webhook Handlers + +#### `/api/webhooks/stripe/route.ts` +- **Methods:** POST +- **Auth:** Stripe signature verification +- **Validation:** Signature + event type routing +- Well-implemented — proper `stripe-signature` header verification. + +#### `/api/webhook/payment/route.ts` +- **Methods:** POST +- **Auth:** Multi-layer: signature verification, amount verification, idempotency check +- **Validation:** Zod schema + constant-time comparison +- **Excellent implementation** — one of the best-secured routes in the codebase. + +| # | Severity | Finding | +|---|----------|---------| +| 22 | **MEDIUM** | Only SSLCommerz signatures are verified (line 148-164). The function returns `false` for all other gateways. If a new gateway is added, developers must remember to add signature verification here. Consider making this extensible. | + +#### `/api/webhooks/sslcommerz/ipn/route.ts` +- **Methods:** POST +- **Auth:** Hash signature verification + API validation +- **Validation:** Amount verification with tolerance +- Well-implemented — proper multi-tenant credential loading. + +#### `/api/webhooks/pathao/route.ts` +- **Methods:** POST +- **Auth:** Query parameter token comparison + +| # | Severity | Finding | +|---|----------|---------| +| 23 | **MEDIUM** | Token comparison (line 34) uses `!==` which is not constant-time. A timing attack could theoretically extract the webhook secret. Use `crypto.timingSafeEqual()` instead. | +| 24 | **LOW** | Error response at line 176 leaks internal error messages: `details: error instanceof Error ? error.message : String(error)`. Webhook error details should not be returned to the caller. | + +#### `/api/webhooks/facebook/route.ts` +- **Methods:** GET (verification), POST (events) +- **Auth:** HMAC SHA-256 signature verification + +| # | Severity | Finding | +|---|----------|---------| +| 25 | **HIGH** | **Timing-unsafe signature comparison:** Line 95 uses `===` for signature comparison: `return signature === \`sha256=\${expected}\``. This is vulnerable to timing attacks. Must use `crypto.timingSafeEqual()`. | +| 26 | **MEDIUM** | `FACEBOOK_APP_SECRET` defaults to empty string (line 15). If not configured, HMAC with empty secret would validate any payload — `validateSignature` would succeed for any input where the caller provides the matching HMAC of empty-secret. The empty-string default should be caught and rejected. | + +#### `/api/webhooks/route.ts` (webhook management) +- Uses mock data — appears to be a placeholder implementation. + +--- + +### 6. `/api/admin/` — Administration Routes + +#### `/api/admin/setup-payment-configs/route.ts` + +| # | Severity | Finding | +|---|----------|---------| +| 27 | **CRITICAL** | **Authentication completely disabled:** Lines 13-25 show the auth check is commented out with `// TODO: Re-enable auth check after initial setup`. This endpoint is fully unauthenticated and creates SSLCommerz payment configurations for ALL organizations. It also exposes hardcoded test credentials in the source code (line 27-28). Any anonymous user can call `GET /api/admin/setup-payment-configs` to inject payment configurations into every org. | + +#### `/api/admin/fix-broken-trials/route.ts` + +| # | Severity | Finding | +|---|----------|---------| +| 28 | **CRITICAL** | **Weak auth via static bearer token:** Auth is a simple `Bearer` token comparison (line 18) against `ADMIN_FIX_TOKEN` env var. If this env var is not set, the endpoint returns 401 — but if set to a weak value, it bypasses all RBAC. This endpoint modifies subscription data for up to 1000 stores. Should use the standard `requireSuperAdmin()` pattern. | + +#### `/api/admin/users/route.ts` +- **Methods:** GET (via `apiHandler({ permission: 'admin:users:read' })`) +- **Auth:** Permission + explicit `isSuperAdmin` check +- **Validation:** Zod schema with sanitized search input, rate limiting +- **Excellent implementation** — double-checks super admin status, sanitizes search input. + +#### `/api/admin/users/[id]/route.ts` +- **Methods:** GET, PATCH, DELETE +- **Auth:** Permission-based via `apiHandler` +- **Validation:** Zod schemas +- **Good safeguards:** Prevents self-deletion, self-superadmin modification, deletion of other super admins +- Well-implemented. + +#### `/api/admin/plans/route.ts` +- **Methods:** GET, POST +- **Auth:** Custom `requireSuperAdmin()` with DB check +- **Validation:** Zod schema for POST +- Properly secured. + +#### `/api/admin/stores/route.ts` +- **Methods:** GET +- **Auth:** `apiHandler({ permission: 'admin:stores:read' })` + +| # | Severity | Finding | +|---|----------|---------| +| 29 | **MEDIUM** | Search parameter (line 11) is used directly in Prisma `contains` without sanitization. Unlike `/api/admin/users` which uses `sanitizeSearchInput`, this route passes raw search input to the query. Prisma parameterizes queries so SQL injection is prevented, but regex injection in `mode: 'insensitive'` queries should still be sanitized for consistency. | + +#### `/api/admin/stats/route.ts` and `/api/admin/system/route.ts` +- Both use `apiHandler` + explicit `isSuperAdmin` DB check +- Both properly double-validate authorization +- Well-implemented. + +--- + +### 7. `/api/store/[slug]/` — Public Storefront Routes + +#### `/api/store/[slug]/route.ts` +- **Methods:** GET (public, no auth) +- Returns public store info only + +| # | Severity | Finding | +|---|----------|---------| +| 30 | **MEDIUM** | Exposes `organizationId` in the public response (line 53). This internal ID could be used by attackers to probe other endpoints that accept `organizationId` as input (e.g., `/api/payments/sslcommerz/initiate`). | + +#### `/api/store/[slug]/orders/route.ts` (Guest Checkout) +- **Methods:** POST with rate limiting (10/min) +- **Auth:** None (guest checkout — expected) +- **Validation:** Comprehensive Zod schemas, server-side price recalculation + +**Strengths:** +- Server-side price enforcement (does not trust client prices) +- Idempotency key support +- Inventory validation inside transaction +- Rate limiting at 10/minute +- Discount code validation with server-calculated amount + +| # | Severity | Finding | +|---|----------|---------| +| 31 | **LOW** | `ipAddress` is stored from `x-forwarded-for` header (line 376) which is client-controllable. Use the rightmost IP or validate against trusted proxy list. | + +#### `/api/store/[slug]/orders/[orderId]/route.ts` + +| # | Severity | Finding | +|---|----------|---------| +| 32 | **CRITICAL** | **Unauthenticated Order Data Exposure (IDOR):** This public endpoint returns full order details (items, prices, payment attempts, addresses, phone numbers) to anyone who knows the order ID. There is no authentication, no email/phone verification (unlike `/api/orders/[id]`), and no rate limiting. An attacker can enumerate order IDs (CUIDs are sequential-ish) and extract customer PII, payment details, and order history for any store. | + +#### `/api/store/[slug]/orders/[orderId]/verify-payment/route.ts` + +| # | Severity | Finding | +|---|----------|---------| +| 33 | **CRITICAL** | **Unauthenticated Payment Status Modification:** Both POST and GET (line 213-215, GET delegates to POST) allow any unauthenticated caller to trigger payment verification and update order payment status to PAID. An attacker can call `POST /api/store/[slug]/orders/[orderId]/verify-payment` for any order — if the SSLCommerz session query returns a false positive or the SSLCommerz API is spoofed, the order is marked as paid without any authentication. Even without spoofing, this is an information disclosure vector revealing payment status. | + +#### `/api/store/[slug]/coupons/validate/route.ts` +- **Methods:** POST (public, no auth — expected for checkout) +- **Validation:** Manual validation +- No issues — read-only coupon validation is acceptable without auth. + +#### `/api/store/[slug]/payment-methods/route.ts` +- **Methods:** GET (public — expected) +- Returns enabled payment methods — no sensitive data exposed. + +--- + +### 8. `/api/checkout/` — Checkout Routes + +#### `/api/checkout/complete/route.ts` +- **Methods:** POST (via `apiHandler({ permission: 'checkout:complete' })`) +- **Auth:** Permission required +- **Validation:** Zod schema + +| # | Severity | Finding | +|---|----------|---------| +| 34 | **MEDIUM** | Requires `checkout:complete` permission, meaning guest checkout cannot use this endpoint — only the store-specific `/api/store/[slug]/orders` route supports guest checkout. This is correct but should be documented to prevent confusion. | + +#### `/api/checkout/validate/route.ts` +- **Methods:** POST (via `apiHandler({ permission: 'checkout:validate' })`) +- Same pattern — properly secured. + +--- + +### 9. `/api/subscriptions/` — Subscription Management + +#### `/api/subscriptions/subscribe/route.ts` +- **Methods:** POST (via `apiHandler({})`) +- **Auth:** Auth required (empty options still enforces auth via `apiHandler`) + +| # | Severity | Finding | +|---|----------|---------| +| 35 | **HIGH** | **No permission check:** The handler uses `apiHandler({})` with no permission specified. Any authenticated user (including CUSTOMER_SUPPORT or DELIVERY_BOY roles) can create subscriptions for arbitrary `customerId` values. Should require `subscriptions:create` permission. | + +#### `/api/subscriptions/cancel/route.ts` +- **Methods:** PATCH +- **Auth:** Session + `getCurrentStoreId()` +- **Validation:** Zod schema +- Properly scoped to current user's store. + +#### `/api/subscriptions/webhook/route.ts` +- **Methods:** POST (no auth — webhook) +- **Auth:** Gateway-specific signature verification via `paymentGateway.verifyWebhook` +- Properly implemented for webhook use case. + +#### `/api/subscriptions/init-trial/route.ts` + +| # | Severity | Finding | +|---|----------|---------| +| 36 | **CRITICAL** | **Production guard relies solely on `NODE_ENV`:** Line 16 checks `process.env.NODE_ENV === 'production'` to disable this endpoint. If `NODE_ENV` is misconfigured (e.g., 'Production', undefined, or 'staging'), any authenticated user can initialize free trial subscriptions for their store repeatedly. The endpoint creates real subscriptions with no idempotency check. | + +--- + +### 10. `/api/media/upload/route.ts` — File Upload + +- **Methods:** POST +- **Auth:** Session + `canManageStoreMedia` store-level check +- **Validation:** MIME type, file extension whitelist, magic byte verification, 5MB size limit + +**Excellent security implementation.** This is one of the most thoroughly secured endpoints: +- Magic byte validation prevents MIME spoofing +- CUID-based filename generation prevents path traversal +- Extension whitelist +- Store-level authorization + +| # | Severity | Finding | +|---|----------|---------| +| 37 | **LOW** | OPTIONS handler returns `Access-Control-Allow-Origin: *` (line 163). This allows any domain to make upload requests. Should be restricted to known storefront domains. | + +--- + +## Cross-Cutting Concerns + +### Rate Limiting + +| Route | Rate Limited | Risk | +|-------|-------------|------| +| `/api/auth/signup` | Yes (authRateLimit) | Low | +| `/api/store/[slug]/orders` | Yes (10/min) | Low | +| `/api/admin/users` | Yes (searchRateLimit) | Low | +| `/api/auth/verify-email` | **No** | Medium | +| `/api/orders/[id]` (unauth GET) | **No** | High | +| `/api/store/[slug]/orders/[orderId]` | **No** | Critical | +| `/api/store/[slug]/orders/[orderId]/verify-payment` | **No** | Critical | +| `/api/payments/sslcommerz/initiate` | **No** | Medium | +| `/api/store/[slug]/coupons/validate` | **No** | Low | + +### CORS Configuration + +| # | Severity | Finding | +|---|----------|---------| +| 38 | **MEDIUM** | No centralized CORS configuration found. The only CORS header is `Access-Control-Allow-Origin: *` on the media upload OPTIONS handler. Next.js API routes do not set CORS headers by default, which means browser-based cross-origin requests from malicious sites will be blocked by default (same-origin policy). However, non-browser clients (scripts, Postman) are unaffected by CORS. Consider adding explicit CORS headers for public storefront endpoints. | + +### Sensitive Data in Responses + +| # | Severity | Finding | +|---|----------|---------| +| 39 | **MEDIUM** | Several routes return full Prisma model data without explicit `select` clauses, potentially exposing internal fields. Examples: `PATCH /api/admin/users/[id]` returns `updatedUser` (line 116) which includes `passwordHash` if not excluded by the Prisma model. Verify all user-facing responses use explicit `select` or DTO mapping. | + +### Console Logging of Sensitive Data + +| # | Severity | Finding | +|---|----------|---------| +| 40 | **LOW** | Multiple routes log request bodies, customer emails, payment details, and internal IDs to console in production. Examples: `/api/orders/route.ts` lines 200-205, `/api/orders/[id]/route.ts` line 148, `/api/products/[id]/route.ts` lines 57-59. These should use structured logging with PII redaction. | + +--- + +## Priority Remediation Plan + +### Immediate (CRITICAL — fix within days) + +1. **Re-enable auth on `/api/admin/setup-payment-configs`** — Delete or protect this endpoint immediately. Remove hardcoded credentials from source code. + +2. **Add authentication to `/api/store/[slug]/orders/[orderId]/route.ts`** — Require email+phone verification matching the order, or require authentication. Add rate limiting. + +3. **Add authentication to `/api/store/[slug]/orders/[orderId]/verify-payment/route.ts`** — Require the order's customer email or phone to match, or restrict to authenticated users. + +4. **Fix `/api/subscriptions/init-trial/route.ts`** — Use `requireSuperAdmin()` instead of `NODE_ENV` check, or delete if no longer needed. + +5. **Replace static token auth on `/api/admin/fix-broken-trials`** — Use standard `requireSuperAdmin()` pattern. + +### Short-term (HIGH — fix within a sprint) + +6. **Add permission check to `/api/subscriptions/subscribe`** — Require `subscriptions:create` permission. + +7. **Fix mass assignment in `/api/products/[id]` PATCH/PUT** — Define explicit Zod schemas for update payloads and whitelist allowed fields. + +8. **Add mass assignment protection to `/api/products/route.ts` POST** — Same as above. + +9. **Add store access verification to `/api/payments/sslcommerz/initiate`** — Verify the authenticated user belongs to the specified `organizationId`/`storeId`. + +10. **Add role check to `/api/payments/configurations` POST** — Require OWNER or ADMIN role. + +11. **Add Zod validation to `/api/payments/configurations` POST** — Validate the `config` object against gateway-specific schemas. + +12. **Add amount verification to Nagad callback** — Compare provider-reported amount against order total. + +13. **Scope Nagad config query by `organizationId`** — Match the bKash pattern. + +14. **Use `crypto.timingSafeEqual` for Facebook webhook signature** — Replace `===` comparison. + +### Medium-term (MEDIUM) + +15. Fix all timing-unsafe comparisons (Pathao webhook token). +16. Add rate limiting to unauthenticated order lookup endpoints. +17. Stop exposing `organizationId` in public store API responses. +18. Sanitize search input consistently across all admin routes. +19. Add explicit permission check to `/api/orders/bulk` PATCH. +20. Validate Facebook `APP_SECRET` is non-empty before HMAC verification. +21. Cap `limit` parameter in `/api/payments/transactions`. +22. Add explicit `select` clauses to all user-facing Prisma queries. +23. Centralize CORS configuration. +24. Derive `storeId` from session where possible instead of client-provided headers/body. + +### Hardening (LOW) + +25. Increase bcrypt cost factor to 12. +26. Expand common password blocklist. +27. Add structured logging with PII redaction. +28. Strip `x-forwarded-for` IP to rightmost trusted value. +29. Restrict media upload CORS to known domains. +30. Remove or gate debug console.log statements behind `NODE_ENV` checks. + +--- + +## Positive Findings (Commendations) + +The following security patterns demonstrate strong security awareness: + +1. **`apiHandler` middleware** — Centralized auth/permission/CSRF/validation reduces the attack surface across 291 routes. +2. **Server-side price enforcement** in guest checkout — Prices are recalculated server-side, preventing client-side price manipulation. +3. **Idempotency key support** on order creation — Prevents duplicate orders on network retries. +4. **Multi-layer webhook validation** in `/api/webhook/payment` — Signature + amount + idempotency is exemplary. +5. **Magic byte validation** on file uploads — Prevents MIME spoofing attacks. +6. **Constant-time comparison** in the payment webhook signature verification. +7. **Tenant-scoped credential loading** for SSLCommerz IPN — Correctly loads store-specific credentials. +8. **Comprehensive Zod validation** across most routes with proper error formatting. +9. **Audit logging** for admin actions and permission checks. +10. **Email normalization** (Gmail dot-stripping) applied consistently across auth flows. diff --git a/docs/cursor/review/00-PROJECT-OVERVIEW.md b/docs/cursor/review/00-PROJECT-OVERVIEW.md new file mode 100644 index 00000000..77869562 --- /dev/null +++ b/docs/cursor/review/00-PROJECT-OVERVIEW.md @@ -0,0 +1,113 @@ +# StormCom — Comprehensive Project Review Overview + +**Project:** StormCom — Multitenant E-commerce SaaS Platform +**Review Date:** 2026-04-01 +**Build Status:** SUCCESS (Next.js 16 production build) +**Total Source Files:** 936 (in `src/`) +**Total API Routes:** 291 (`route.ts` files) +**Total Page Routes:** 111 (static + dynamic) +**Database Models:** 42 Prisma models + 24 enums +**Migration Files:** 38 SQL migrations + +--- + +## Tech Stack Summary + +| Layer | Technology | Version | +|-------|-----------|---------| +| Framework | Next.js (App Router) | ^16.1.6 | +| Language | TypeScript | 5.9.3 | +| UI Library | React | 19.2.4 | +| Styling | Tailwind CSS v4 | ^4 | +| ORM | Prisma | ^7.5.0 | +| Database | PostgreSQL | via `@prisma/adapter-pg` | +| Auth | NextAuth.js v4 | ^4.24.13 | +| Hosting | Vercel | Analytics + Blob + Speed Insights | +| Email | Resend | ^6.9.4 | +| Payments | Stripe, SSLCommerz, bKash, Nagad | Various | +| Caching | Redis (ioredis + Upstash) | ^5.10.1 / ^1.37.0 | +| AI | Ollama | ^0.6.3 | +| Search | Elasticsearch (optional) | ^8.11.0 | +| State | Zustand + Zundo | ^5.0.11 / ^2.3.0 | +| Forms | React Hook Form + Zod | ^7.71.2 / ^4.3.6 | +| Charts | Recharts | ^3.8.0 | +| UI Components | Radix UI (individual packages) | Various | +| Icons | Lucide React + Tabler Icons | Various | +| Testing | Vitest + Playwright | ^4.0.16 / ^1.58.2 | + +--- + +## Repository Structure + +``` +/workspace +├── docs/cursor/ # Documentation (3 existing + new review docs) +├── prisma/ # Database schema, seeds, 38 migrations +│ ├── schema.prisma # 2014 lines, 42 models, 24 enums +│ ├── seed.mjs # Primary seed script (2017 lines) +│ ├── seed-new.mjs # Alternative seed (1524 lines) +│ ├── seed.ts # TypeScript seed (1340 lines) +│ ├── seed-plans-only.mjs +│ ├── seeds/subscription-plans.mjs +│ └── migrations/ # 38 migration files +├── src/ +│ ├── app/ # Next.js App Router pages & API routes +│ │ ├── api/ # 291 route.ts files +│ │ ├── admin/ # Super admin pages +│ │ ├── dashboard/ # Merchant dashboard pages +│ │ ├── store/[slug]/ # Public storefront +│ │ ├── (auth)/ # Auth pages (login, signup, etc.) +│ │ ├── chat/ # AI Chat page +│ │ ├── checkout/ # Checkout flow +│ │ ├── settings/ # User/AI/API settings +│ │ └── ... # Other pages +│ ├── components/ # React components (~247 files) +│ │ ├── ui/ # Shadcn/Radix UI primitives (50 files) +│ │ ├── admin/ # Admin panel components +│ │ ├── dashboard/ # Dashboard storefront editor +│ │ ├── storefront/ # Public storefront components +│ │ ├── integrations/ # Facebook, SSLCommerz +│ │ ├── subscription/ # Subscription management +│ │ └── ... # Other component groups +│ ├── lib/ # Core libraries (~177 files) +│ │ ├── services/ # Business logic service layer (21 services) +│ │ ├── security/ # Security utilities +│ │ ├── payments/ # Payment providers +│ │ ├── subscription/ # Subscription lifecycle +│ │ ├── integrations/ # Facebook integration +│ │ ├── landing-pages/ # Landing page templates +│ │ ├── storefront/ # Storefront configuration +│ │ ├── cache/ # Cache service +│ │ ├── i18n/ # Internationalization +│ │ └── ... # Core utilities +│ ├── hooks/ # React hooks (10 files) +│ ├── middleware/ # Custom middleware (1 file) +│ ├── test/ # Test files +│ └── types/ # TypeScript declarations +├── next.config.ts # Next.js configuration +├── tsconfig.json # TypeScript configuration +├── postcss.config.mjs # PostCSS + Tailwind +├── package.json # Dependencies & scripts +├── .env.example # Environment template +└── .env.production.example +``` + +--- + +## Documentation Index + +All review documents are located in `docs/cursor/review/`: + +| # | Document | Description | +|---|----------|-------------| +| 00 | `00-PROJECT-OVERVIEW.md` | This file — project summary and document index | +| 01 | `01-COMPREHENSIVE-CODE-REVIEW.md` | Line-by-line code review findings | +| 02 | `02-DATABASE-SCHEMA-REVIEW.md` | Prisma schema analysis | +| 03 | `03-DEPENDENCY-AUDIT.md` | Package.json dependency validation | +| 04 | `04-ROUTE-CROSS-VALIDATION.md` | API + Page routes with build verification | +| 05 | `05-SECURITY-VULNERABILITIES.md` | Security audit findings | +| 06 | `06-TRACEABILITY-MATRIX.md` | Requirements traceability matrix | +| 07 | `07-CRUD-MATRIX.md` | CRUD operations matrix | +| 08 | `08-ARCHITECTURE-BLUEPRINT.md` | Architecture and interaction map | +| 09 | `09-BEST-PRACTICES-SUGGESTIONS.md` | Latest best practices and fix guidelines | +| 10 | `10-PROGRESS-STATUS.md` | Review progress tracking | diff --git a/docs/cursor/review/01-COMPREHENSIVE-CODE-REVIEW.md b/docs/cursor/review/01-COMPREHENSIVE-CODE-REVIEW.md new file mode 100644 index 00000000..f8208fd8 --- /dev/null +++ b/docs/cursor/review/01-COMPREHENSIVE-CODE-REVIEW.md @@ -0,0 +1,319 @@ +# StormCom — Comprehensive Code Review + +**Reviewed:** 936 files in `src/` across all subdirectories +**Review Date:** 2026-04-01 + +--- + +## Table of Contents + +1. [Core Library Review (`src/lib/`)](#1-core-library-review) +2. [API Routes Review (`src/app/api/`)](#2-api-routes-review) +3. [Service Layer Review (`src/lib/services/`)](#3-service-layer-review) +4. [Component Review (`src/components/`)](#4-component-review) +5. [Payment Integration Review](#5-payment-integration-review) +6. [Hooks & State Review](#6-hooks--state-review) +7. [Cross-Cutting Findings](#7-cross-cutting-findings) + +--- + +## 1. Core Library Review + +### 1.1 Authentication (`src/lib/auth.ts`) + +| Severity | Finding | Location | +|----------|---------|----------| +| **CRITICAL** | XSS in magic-link email: `host` and `url` injected directly into HTML without escaping | Line 53 | +| **HIGH** | Account status not rechecked on token refresh — suspended user retains session until JWT expiry | Lines 162-264 | +| **MEDIUM** | Sensitive data logged: full magic link URL (contains auth token) logged to stdout | Line 46 | +| **MEDIUM** | `parseInt` without `isNaN` guard on `MAX_JWT_MEMBERSHIP_FETCH` — `NaN` passed to Prisma `take` | Line 33 | +| **LOW** | Dynamic `import('./permissions')` in hot path (JWT callback) — should be static top-level import | Line 246 | + +### 1.2 Prisma Client (`src/lib/prisma.ts`) + +| Severity | Finding | Location | +|----------|---------|----------| +| **HIGH** | No connection pool size control — serverless functions exhaust DB connections | Lines 16-21 | +| **MEDIUM** | No graceful shutdown hook (`$disconnect`) — connections leak on process shutdown | Entire file | +| **LOW** | Verbose query logging in dev includes sensitive WHERE clauses | Line 20 | + +### 1.3 Permissions (`src/lib/permissions.ts`) + +| Severity | Finding | Location | +|----------|---------|----------| +| **MEDIUM** | `:own` scope suffix defined in permission strings but never enforced by `hasPermission()` | Lines 269-287 | +| **LOW** | Hardcoded role lists — new roles silently default to CUSTOMER level without compile-time safety | Lines 370-373 | + +### 1.4 Multi-Tenancy (`src/lib/multi-tenancy.ts`) + +| Severity | Finding | Location | +|----------|---------|----------| +| **HIGH** | Unbounded query for user organizations — no `take` limit | Lines 112-127 | +| **MEDIUM** | Race condition in `ensureUniqueSlug` — TOCTOU with no retry on unique constraint violation | Lines 144-154 | +| **MEDIUM** | No input validation on slug/userId parameters | Line 40 | + +### 1.5 API Middleware (`src/lib/api-middleware.ts`) + +| Severity | Finding | Location | +|----------|---------|----------| +| **HIGH** | CSRF validation missing from `withAuth`/`withPermission` wrappers — only present in `apiHandler` | Lines 385-417, 490-505 | +| **MEDIUM** | Permission string leaked in error messages reveals internal model to attackers | Lines 332-333 | +| **MEDIUM** | Content-Type restriction blocks `multipart/form-data` file uploads | Lines 461-466 | +| **LOW** | `sortOrder` query param cast bypasses validation — arbitrary values pass through | Line 607 | + +### 1.6 Security Module (`src/lib/security.ts`) + +| Severity | Finding | Location | +|----------|---------|----------| +| **HIGH** | `constantTimeCompare` early-returns on length mismatch — leaks length info, not constant-time | Lines 139-150 | +| **MEDIUM** | SQL injection regex rejects legitimate input (quotes in names like `O'Brien`) | Lines 231-239 | +| **MEDIUM** | Token generation has modular bias (charset length 62 vs 256 byte range) | Lines 155-166 | +| **LOW** | CUID regex validation rejects valid CUID2 IDs (variable length, different prefix) | Lines 71-75 | + +### 1.7 CSRF Protection (`src/lib/security/csrf.ts`) + +| Severity | Finding | Location | +|----------|---------|----------| +| **MEDIUM** | CSRF token not tied to session (double-submit without signing) — subdomain attacks possible | Lines 40-59 | +| **MEDIUM** | `__Host-` cookie prefix requires `Secure` flag always, but only set in production — dev CSRF non-functional | Line 17, 52 | + +### 1.8 Rate Limiting (THREE separate implementations) + +| File | Backend | Severity | Finding | +|------|---------|----------|---------| +| `rate-limiter.ts` | PostgreSQL DB | **CRITICAL** | Database-backed rate limiting causes N+1 write amplification, lock contention on every API request | +| `rate-limit.ts` | Upstash Redis | **MEDIUM** | Fail-open on Redis error allows all requests through | +| `security/rate-limit.ts` | ioredis + in-memory | **MEDIUM** | Serverless in-memory fallback is useless (fresh store per cold start) | +| All three | — | **HIGH** | Three incompatible rate-limiting systems with different APIs, stores, and failure modes | + +### 1.9 Encryption (`src/lib/encryption.ts`) + +| Severity | Finding | Location | +|----------|---------|----------| +| **HIGH** | AES-256-CBC without authentication tag — vulnerable to bit-flipping attacks | Line 16 | +| **MEDIUM** | CBC padding oracle vulnerability on decryption errors | Lines 64-89 | +| **MEDIUM** | Fragile `split(':')` parsing of encrypted text | Line 71 | + +### 1.10 Redis (`src/lib/redis.ts`) + +| Severity | Finding | Location | +|----------|---------|----------| +| **HIGH** | Client getters throw on uninitialized state — no lazy-init pattern | Lines 106-133 | +| **MEDIUM** | Redis URL (with password) may be logged in connection errors | Lines 174-184 | +| **MEDIUM** | PubSub/RateLimit clients lack connection timeout settings | Lines 191-219 | + +### 1.11 Cache (`src/lib/cache.ts`) + +| Severity | Finding | Location | +|----------|---------|----------| +| **HIGH** | `invalidateCacheByPattern` uses Redis `KEYS` command — blocks server with large keyspaces | Line 352 | +| **MEDIUM** | Cache stampede — no locking on concurrent fetches for expired keys | Lines 171-189 | +| **MEDIUM** | `null` values cannot be cached — causes repeated DB queries for non-existent resources | Line 128 | +| **MEDIUM** | Mixed stats tracking (in-memory vs Redis) — never synchronized | Lines 78-83, 197 | + +### 1.12 Environment (`src/lib/env.ts`) + +| Severity | Finding | Location | +|----------|---------|----------| +| **CRITICAL** | `validateEnv()` runs at import time — crashes app if env vars missing during build/test | Line 51 | +| **MEDIUM** | Only 5 env vars validated — missing critical vars like `CREDENTIALS_ENCRYPTION_KEY`, Redis URLs | Lines 8-24 | + +### 1.13 Error Handler (`src/lib/error-handler.ts`) + +| Severity | Finding | Location | +|----------|---------|----------| +| **HIGH** | `error.message` returned verbatim in 500 responses — leaks file paths, DB schema | Lines 82-92 | +| **MEDIUM** | Prisma P2002 error leaks database column names to client | Lines 114-122 | + +### 1.14 Money (`src/lib/money.ts`) + +| Severity | Finding | Location | +|----------|---------|----------| +| **MEDIUM** | No integer validation on inputs — floating point values produce incorrect results silently | Lines 99-115 | +| **LOW** | Hardcoded `MINOR_UNIT_FACTOR = 100` — incorrect for currencies like JPY (0 decimals) | Line 29 | + +### 1.15 Webhook Delivery (`src/lib/webhook-delivery.ts`) + +| Severity | Finding | Location | +|----------|---------|----------| +| **CRITICAL** | SSRF vulnerability — no URL validation on user-provided webhook URLs, can target internal APIs | Lines 121-127 | +| **HIGH** | `setTimeout` retries don't survive serverless function lifecycle | Lines 282-285 | +| **HIGH** | Unhandled promise in async setTimeout callback | Lines 282-285 | +| **MEDIUM** | Event matching uses `contains` on comma-separated string — substring false positives | Lines 351-352 | +| **MEDIUM** | Fire-and-forget delivery — in-flight deliveries lost on process shutdown | Lines 377-382 | + +### 1.16 Email Service (`src/lib/email-service.ts`) + +| Severity | Finding | Location | +|----------|---------|----------| +| **HIGH** | No rate limiting on email sending — abuse can exhaust sending quota or blacklist domain | Entire file | +| **MEDIUM** | No HTML escaping on template parameters — XSS in emails | Lines 68-69 | +| **MEDIUM** | Non-null assertion operator `resend!` throughout — crashes if guard removed | Lines 64, 90, 117 | +| **LOW** | Production domains hardcoded as fallbacks | Lines 29-31 | + +### 1.17 Session Management + +| Severity | Finding | Location | +|----------|---------|----------| +| **HIGH** | Four different session-fetching approaches in codebase — inconsistent, duplicate lookups | Multiple files | +| **MEDIUM** | No request-scoped context — 3-5+ DB queries per request just for auth/authorization | Cross-cutting | + +--- + +## 2. API Routes Review + +### 2.1 Critical Authentication Issues + +| Severity | Route | Finding | +|----------|-------|---------| +| **CRITICAL** | `/api/admin/setup-payment-configs` | Authentication **entirely commented out** — anonymous access to payment config injection | +| **CRITICAL** | `/api/store/[slug]/orders/[orderId]` | Full order PII (addresses, payment attempts) exposed to unauthenticated callers | +| **CRITICAL** | `/api/store/[slug]/orders/[orderId]/verify-payment` | Unauthenticated payment verification — can mark orders as paid | +| **CRITICAL** | `/api/subscriptions/init-trial` | Production guard relies on `NODE_ENV` string only — misconfiguration allows unlimited trials | +| **CRITICAL** | `/api/admin/fix-broken-trials` | Uses static bearer token instead of RBAC — modifies up to 1000 subscriptions | + +### 2.2 Authorization & Access Control + +| Severity | Route | Finding | +|----------|-------|---------| +| **HIGH** | `/api/products` POST/PATCH | Mass assignment — raw request body passed to Prisma without field whitelisting | +| **HIGH** | `/api/payments/sslcommerz/initiate` | Missing store access verification — attacker can initiate payments against any store | +| **HIGH** | `/api/payments/configurations` POST | Any authenticated user can modify payment gateway credentials | +| **HIGH** | `/api/payments/nagad/callback` | Lacks amount verification — payment could be confirmed for wrong amount | +| **HIGH** | `/api/webhooks/facebook` | Timing-unsafe signature comparison — vulnerable to timing attacks | +| **HIGH** | `/api/subscriptions/subscribe` | No permission check — any role can create subscriptions | +| **HIGH** | `/api/orders/[id]` GET | IDOR via email-based access without rate limiting on unauthenticated endpoint | + +### 2.3 Input Validation Gaps + +| Severity | Route | Finding | +|----------|-------|---------| +| **MEDIUM** | Multiple POST/PUT routes | Missing Zod schema validation — rely on Prisma implicit validation only | +| **MEDIUM** | `/api/search` | No search query length limit — potential for expensive regex/LIKE queries | +| **MEDIUM** | `/api/media/upload` | File type validated by magic bytes but max file size not enforced at route level | +| **LOW** | Pagination params | Some routes accept unbounded `limit` params — can request all records | + +### 2.4 Positive Patterns Found + +The codebase demonstrates several strong practices: +- Server-side price enforcement in checkout flow +- Multi-layer webhook validation in Stripe handler +- Magic byte file upload verification for media uploads +- Centralized CSRF protection via `apiHandler` middleware +- Comprehensive Zod validation on most business-critical routes + +--- + +## 3. Service Layer Review + +### 3.1 Critical Service Findings + +| Severity | Service | Finding | +|----------|---------|---------| +| **CRITICAL** | `attribute.service.ts` | Tenant isolation leak — queries missing `storeId` filter allow cross-tenant attribute access | +| **CRITICAL** | `order-processing.service.ts` | Transaction atomicity broken — inventory deduction and order creation not wrapped in single transaction | +| **HIGH** | `product.service.ts` | Bulk delete lacks confirmation/soft-delete — permanent data loss possible | +| **HIGH** | `checkout.service.ts` | Race condition on inventory check vs. order placement — overselling possible | +| **HIGH** | `discount.service.ts` | Coupon usage increment not atomic with order creation — concurrent usage can exceed `maxUses` | +| **MEDIUM** | `customer.service.ts` | Email uniqueness check before insert is TOCTOU — concurrent signups can create duplicates | +| **MEDIUM** | `analytics.service.ts` | Unbounded date range queries — no maximum window limit | +| **MEDIUM** | `search.service.ts` | Elasticsearch client created per-call — no connection pooling | +| **MEDIUM** | `pathao.service.ts` | API credentials stored in plain text in Store model | + +### 3.2 Transaction Handling + +Many multi-step operations lack Prisma `$transaction` wrappers: +- Order creation + inventory deduction + payment processing +- Subscription upgrade + plan change + invoice creation +- Bulk product import + category/brand creation +- Customer creation + order history migration + +--- + +## 4. Component Review + +### 4.1 Dead Code & Artifacts + +| File | Issue | +|------|-------| +| `src/components/landing-pages/landing-page-editor-client.tsx.bak` | Backup file committed to repository — should be deleted | +| `src/components/product-quick-view.tsx` | Duplicate of `src/components/products/product-quick-view.tsx` | +| `src/components/price-range-filter.tsx` | Duplicate of `src/components/products/price-range-filter.tsx` | + +### 4.2 Client/Server Component Issues + +| Severity | Component | Issue | +|----------|-----------|-------| +| **MEDIUM** | Multiple dashboard pages | Large client components that could leverage server components for data fetching | +| **MEDIUM** | Store layout | Heavy client-side data fetching that should use React Server Components | +| **LOW** | `ClientOnly.tsx` | Wrapper exists but not consistently used for client-only components | + +### 4.3 State Management + +- Zustand stores (`cart-store.ts`, `appearance-editor-store.ts`) are well-structured +- Zundo provides undo/redo for the appearance editor +- Some components still use local state where shared state would be better (e.g., notification count) + +--- + +## 5. Payment Integration Review + +### 5.1 Payment Orchestrator (`src/lib/payments/payment-orchestrator.ts`) + +| Severity | Finding | +|----------|---------| +| **HIGH** | No idempotency key on payment initiation — duplicate payments possible on retry | +| **MEDIUM** | Amount calculated from order data rather than locked at intent creation time | + +### 5.2 Provider-Specific Findings + +| Provider | Severity | Finding | +|----------|----------|---------| +| **Stripe** | MEDIUM | Webhook endpoint secret not rotated — long-lived secret | +| **SSLCommerz** | HIGH | Test credentials hardcoded in setup route (admin/setup-payment-configs) | +| **bKash** | CRITICAL | Payment persistence is non-functional — provider class is skeleton/stub code | +| **Nagad** | CRITICAL | Payment persistence is non-functional — provider class is skeleton/stub code | +| **All** | MEDIUM | No circuit breaker pattern — failed provider doesn't trigger failover | + +--- + +## 6. Hooks & State Review + +| Hook | Status | Notes | +|------|--------|-------| +| `useApiQuery.ts` | OK | Generic API fetching hook with caching | +| `useAsyncOperation.ts` | OK | Loading/error state management | +| `use-autosave.ts` | OK | Debounced auto-save | +| `use-keyboard-shortcuts.ts` | OK | Keyboard shortcut registry | +| `useMetaTracking.ts` | OK | Meta pixel tracking | +| `use-mobile.ts` | OK | Responsive breakpoint detection | +| `useOrderStream.ts` | MEDIUM | SSE connection not cleaned up on unmount in some cases | +| `usePagination.ts` | OK | Pagination state management | +| `use-performance.tsx` | OK | Performance monitoring hook | +| `use-permissions.ts` | OK | Client-side permission checking | + +--- + +## 7. Cross-Cutting Findings + +### 7.1 Duplicate Function Names + +Multiple functions with the same name exist across different modules: +- `checkRateLimit` — 3 different implementations +- `getRateLimitHeaders` — 2 implementations +- `getClientIdentifier` — 2 implementations +- `sanitizeHtml` / `sanitizeUrl` — 2 implementations each +- `verifyStoreAccess` — 2 implementations + +### 7.2 Inconsistent Patterns + +- Session fetching: 4 different approaches used inconsistently +- Error response format: `createErrorResponse`, `errorResponse`, `NextResponse.json` used interchangeably +- Prisma query patterns: Some services use raw queries, others use generated client +- Cache key formats: Inconsistent naming conventions across modules + +### 7.3 Configuration Issues + +- `next.config.ts` has `typescript.ignoreBuildErrors: true` — type errors ignored in production builds +- CSP header uses `unsafe-eval` and `unsafe-inline` — weakens XSS protection +- `X-Frame-Options: DENY` is overridden to `SAMEORIGIN` for store paths — inconsistent diff --git a/docs/cursor/review/02-DATABASE-SCHEMA-REVIEW.md b/docs/cursor/review/02-DATABASE-SCHEMA-REVIEW.md new file mode 100644 index 00000000..bb397a28 --- /dev/null +++ b/docs/cursor/review/02-DATABASE-SCHEMA-REVIEW.md @@ -0,0 +1,132 @@ +# StormCom — Database Schema Review + +**Schema File:** `prisma/schema.prisma` (2014 lines) +**Provider:** PostgreSQL +**Models:** 42 +**Enums:** 24 +**Migrations:** 38 + +--- + +## 1. Schema Architecture Overview + +### 1.1 Entity Groups + +| Group | Models | Description | +|-------|--------|-------------| +| **Auth & Users** | User, Account, Session, VerificationToken, PendingSignup | NextAuth.js adapter + custom user fields | +| **Organization** | Organization, Membership, Project, ProjectMember | Multi-tenant org structure | +| **Store & Commerce** | Store, StoreStaff, Product, ProductVariant, Category, Brand, ProductAttribute, ProductAttributeValue | Core e-commerce | +| **Orders & Payments** | Order, OrderItem, PaymentAttempt, PaymentConfiguration, IdempotencyKey, IdempotencyRecord | Order processing | +| **Inventory** | InventoryLog, InventoryReservation, InventoryReservationItem | Stock management | +| **Customers** | Customer, Review, DiscountCode | Customer relations | +| **Fulfillment** | Fulfillment | Shipping/delivery | +| **Webhooks** | Webhook, WebhookDelivery | Outbound event delivery | +| **Subscription** | SubscriptionPlanModel, Subscription, SubscriptionLog, SubPayment, Invoice, InvoiceItem | SaaS billing | +| **Facebook** | FacebookIntegration, FacebookProduct, FacebookInventorySnapshot, FacebookOrder, FacebookConversation, FacebookMessage, FacebookWebhookLog, FacebookOAuthState, FacebookCheckoutSession, FacebookBatchJob, ConversionEvent | Facebook commerce | +| **Chat/AI** | ChatMessage, ChatSession, ChatAttachment, ChatUsageLog, OllamaConfig | AI assistant | +| **Landing Pages** | LandingPage, LandingPageVersion | Marketing pages | +| **Analytics** | PerformanceMetric, SearchAnalytics, ApiUsageLog, CacheMetric, AnalyticsAlert | Observability | +| **Security** | AuditLog, RateLimit, ApiToken, CustomRole, CustomRoleRequest | Access control | +| **Platform** | PlatformActivity, StoreRequest, Notification | Admin operations | + +### 1.2 Relationship Map + +``` +User ──┬── Account (1:N) + ├── Session (1:N) + ├── Membership ──── Organization ──── Store (1:1) + ├── StoreStaff ──── Store + ├── ChatMessage ──── ChatSession + ├── OllamaConfig (1:1) + └── Notification (1:N) + +Store ──┬── Product ──┬── ProductVariant (1:N) + │ ├── OrderItem + │ ├── Review + │ └── ProductAttributeValue + ├── Order ──┬── OrderItem (1:N) + │ ├── PaymentAttempt (1:N) + │ ├── Fulfillment (1:N) + │ └── InventoryReservation (1:N) + ├── Category (1:N, self-referencing tree) + ├── Brand (1:N) + ├── Customer ──── Order (1:N) + ├── DiscountCode (1:N) + ├── Webhook ──── WebhookDelivery + ├── Subscription ──── SubscriptionPlanModel + ├── FacebookIntegration (1:1) + └── LandingPage (1:N) +``` + +--- + +## 2. Schema Findings + +### 2.1 Design Issues + +| Severity | Finding | Details | +|----------|---------|---------| +| **HIGH** | JSON stored as `String` type | `storefrontConfig`, `storefrontConfigDraft`, `storefrontConfigVersions`, `features` (SubscriptionPlan), `events` (Webhook), `permissions` (CustomRole/Request) — all stored as `String` instead of `Json`, losing type safety and query capabilities | +| **HIGH** | No Row-Level Security (RLS) | Multi-tenancy relies entirely on application-level `storeId` filtering — a single missed filter leaks data across tenants | +| **MEDIUM** | `Store` model overloaded | 50+ fields including Pathao credentials, storefront config (potentially megabytes of JSON), and subscription data — should be normalized | +| **MEDIUM** | Inconsistent soft-delete | Some models have `deletedAt` (Product, Category, Brand, Customer, Order, DiscountCode, Webhook), others don't (Review, Fulfillment, StoreStaff) — partial soft-delete creates confusion | +| **MEDIUM** | `images` field as `String` on Product | Image arrays stored as JSON string — no validation, no queryability | +| **MEDIUM** | No composite unique on `Review` | Same customer can review same product multiple times — missing `@@unique([productId, customerId])` | +| **LOW** | `shippingAddress`/`billingAddress` as `String` | Address data stored as unstructured JSON string — should be structured with separate fields or a JSON type | +| **LOW** | Mixed naming conventions | `storefrontConfig` (camelCase) vs `custom_role_requests` (`@@map` to snake_case) — inconsistent table naming | + +### 2.2 Missing Indexes + +| Model | Suggested Index | Reason | +|-------|-----------------|--------| +| `WebhookDelivery` | `@@index([createdAt])` | Cleanup queries filter by date | +| `FacebookProduct` | `@@index([catalogId, syncStatus])` | Catalog sync operations | +| `LandingPageVersion` | Already indexed — OK | | +| `InvoiceItem` | Already indexed — OK | | +| `PlatformActivity` | `@@index([entityType, entityId])` | Activity lookup by entity | + +### 2.3 Seed Script Issues + +| Severity | File | Finding | +|----------|------|---------| +| **MEDIUM** | `seeds/subscription-plans.mjs` | Uses `priceMonthly`, `displayOrder` fields that **don't exist** in current schema (`monthlyPrice`, `sortOrder`) — this seed would fail at runtime | +| **MEDIUM** | `seed.mjs` vs `seed-new.mjs` | Two similar seed files with minor differences — should be consolidated | +| **LOW** | `seed.ts` | TypeScript seed exists alongside `.mjs` versions — `package.json` references `seed.mjs` only | +| **LOW** | `seed-plans-only.mjs` | Uses `.catch(() => null)` silently swallowing creation errors | + +### 2.4 Migration History + +38 migrations spanning 2025-12-01 to 2026-03-31. Notable: +- Initial migration creates full schema +- Multiple Pathao-related migrations suggest iterative integration +- Float-to-Int money conversion migration (`20260228`) — good practice for monetary amounts +- Stock quantity and performance indexes added recently (`20260331`) + +--- + +## 3. Enum Review + +| Enum | Values | Notes | +|------|--------|-------| +| `AccountStatus` | PENDING, APPROVED, REJECTED, SUSPENDED, DELETED | OK | +| `Role` | 13 values | Comprehensive role hierarchy — `DELIVERY_BOY` naming could be gender-neutral | +| `ProductStatus` | DRAFT, ACTIVE, ARCHIVED | Missing `INACTIVE` or `OUT_OF_SEASON` | +| `OrderStatus` | 8 values | OK — covers full lifecycle | +| `PaymentStatus` | 6 values | OK | +| `PaymentMethod` | 5 values | Missing `WALLET`, `UPI` for South Asian markets | +| `PaymentGateway` | STRIPE, SSLCOMMERZ, MANUAL, BKASH, NAGAD | OK for target market | +| `ShippingStatus` | 9 values | Overlaps with `FulfillmentStatus` (same 9 values) — redundant | +| `DiscountType` | NONE, PERCENTAGE, FIXED_AMOUNT, FIXED, FREE_SHIPPING | `FIXED` and `FIXED_AMOUNT` are likely duplicates | +| `SubscriptionStatus` | 7 values | OK | +| `NotificationType` | 26 values | Well-granulated | + +--- + +## 4. Data Integrity Concerns + +1. **Orphaned Records**: `OrderItem.productId` is nullable (product deleted) but no cleanup job exists for orphans +2. **Circular References**: `FacebookCheckoutSession` references both `Store` and `Order`, but `Order` also has the relationship — potential circular cascade +3. **Money Representation**: All monetary fields are `Int` (minor units) — good practice, but `platformFeePercent` on `PaymentConfiguration` is `Float` — inconsistent +4. **No `updatedAt` on**: `WebhookDelivery`, `PendingSignup`, `VerificationToken`, `FacebookWebhookLog`, `FacebookOAuthState` — can't track modification time +5. **`Review.storeId`**: Redundant since Product already has `storeId` — query convenience vs. normalization trade-off diff --git a/docs/cursor/review/03-DEPENDENCY-AUDIT.md b/docs/cursor/review/03-DEPENDENCY-AUDIT.md new file mode 100644 index 00000000..de22c2be --- /dev/null +++ b/docs/cursor/review/03-DEPENDENCY-AUDIT.md @@ -0,0 +1,166 @@ +# StormCom — Dependency Audit Report + +**Total Dependencies:** 84 (56 production + 28 dev) +**Audit Date:** 2026-04-01 +**npm audit:** 3 low severity vulnerabilities + +--- + +## 1. Production Dependencies + +### 1.1 Actively Used (Verified) + +| Package | Version | Import Count | Primary Usage | +|---------|---------|-------------|---------------| +| next | ^16.1.6 | 504 | Framework core | +| react / react-dom | 19.2.4 | 327 | UI rendering | +| @prisma/client | ^7.5.0 | 77 | Database ORM | +| next-auth | ^4.24.13 | 255 | Authentication | +| zod | ^4.3.6 | 147 | Schema validation | +| lucide-react | ^0.577.0 | 212 | Primary icon library | +| @tabler/icons-react | ^3.40.0 | 57 | Secondary icon library | +| sonner | ^2.0.7 | 100 | Toast notifications | +| date-fns | ^4.1.0 | 26 | Date formatting | +| @paralleldrive/cuid2 | ^3.3.0 | 12 | ID generation | +| react-hook-form | ^7.71.2 | 10 | Form management | +| @hookform/resolvers | ^5.2.2 | 9 | Form validation resolvers | +| recharts | ^3.8.0 | 8 | Data visualization | +| class-variance-authority | ^0.7.1 | 8 | Component variants | +| @dnd-kit/* (4 packages) | Various | 15 total | Drag & drop | +| All @radix-ui/* (24 packages) | Various | 1-5 each | UI primitives | +| zustand | ^5.0.11 | 3 | State management | +| stripe / @stripe/* | Various | 5 total | Payment processing | +| bcryptjs | ^3.0.3 | 3 | Password hashing | +| resend | ^6.9.4 | 3 | Email delivery | +| @upstash/redis | ^1.37.0 | 3 | Serverless Redis | +| ioredis | ^5.10.1 | 2 | TCP Redis | +| next-themes | ^0.4.6 | 2 | Dark/light mode | +| @vercel/analytics | ^2.0.0 | 2 | Usage analytics | +| isomorphic-dompurify | ^3.1.0 | 2 | XSS sanitization | +| ollama | ^0.6.3 | 5 | AI chat | +| @tanstack/react-table | ^8.21.3 | 4 | Data tables | + +### 1.2 Low-Usage but Valid + +| Package | Version | Import Count | Usage | +|---------|---------|-------------|-------| +| @elastic/elasticsearch | ^8.11.0 | 1 | Dynamic import — Elasticsearch optional backend | +| @monaco-editor/react | ^4.7.0 | 1 | Custom CSS editor in storefront | +| @react-pdf/renderer | ^4.3.2 | 3 | Invoice PDF generation | +| @socket.io/redis-adapter | ^8.3.0 | 1 | WebSocket Redis adapter (code exists but not wired to server) | +| @tanstack/react-virtual | ^3.13.21 | 1 | Virtual scrolling | +| @vercel/blob | ^2.3.1 | 1 | File storage | +| @vercel/speed-insights | ^2.0.0 | 1 | Performance monitoring | +| clsx | ^2.1.1 | 1 | Class merging | +| cmdk | ^1.1.1 | 1 | Command palette | +| embla-carousel-react | ^8.6.0 | 1 | Storefront carousel | +| jsonwebtoken | ^9.0.3 | 1 | WebSocket JWT auth | +| papaparse | ^5.5.3 | 1 | CSV product import | +| react-colorful | ^5.6.1 | 1 | Color picker | +| react-day-picker | ^9.14.0 | 1 | Calendar component | +| react-resizable-panels | ^4.7.2 | 1 | Panel layout | +| socket.io | ^4.8.3 | 1 | WebSocket server | +| swagger-ui-dist | ^5.32.1 | 1 | API docs viewer | +| tailwind-merge | ^3.5.0 | 1 | Tailwind class merging | +| vaul | ^1.1.2 | 1 | Drawer component | +| zundo | ^2.3.0 | 1 | Zustand undo/redo | + +### 1.3 Unused / Candidates for Removal + +| Package | Version | Import Count | Reason | +|---------|---------|-------------|--------| +| **radix-ui** | ^1.4.3 | **0** | Umbrella package — individual `@radix-ui/*` packages cover all usage | +| **react-is** | ^19.0.0 | **0** | Transitive peer dependency of Recharts — not directly needed | +| **pg** | ^8.20.0 | **0** | Driver for `@prisma/adapter-pg` — indirect dependency, could be in devDependencies | +| **nodemailer** | ^8.0.4 | **0** | Peer for NextAuth email provider — not directly imported | + +### 1.4 Duplicate/Overlapping Dependencies + +| Concern | Packages | Recommendation | +|---------|----------|----------------| +| **Two Redis clients** | ioredis + @upstash/redis | ioredis for traditional, Upstash for edge/serverless — intentional but adds complexity | +| **Two icon libraries** | lucide-react (212 imports) + @tabler/icons-react (57 imports) | Consolidate to one library to reduce bundle size | +| **Umbrella + individuals** | `radix-ui` + 24 individual `@radix-ui/*` packages | Remove umbrella package | + +--- + +## 2. Dev Dependencies + +### 2.1 Actively Used + +| Package | Version | Usage | +|---------|---------|-------| +| prisma | ^7.5.0 | CLI for migrations | +| typescript | 5.9.3 | Compiler | +| tailwindcss | ^4 | CSS framework | +| @tailwindcss/postcss | ^4 | PostCSS plugin | +| eslint + eslint-config-next | Various | Linting | +| vitest + @vitest/coverage-v8 | Various | Unit testing | +| @playwright/test + playwright | Various | E2E testing | +| @testing-library/react + jest-dom | Various | Component testing | +| @vitejs/plugin-react | ^5.1.4 | Vitest React support | +| vite-tsconfig-paths | ^6.1.1 | Path aliases in Vitest | +| vitest-mock-extended | ^3.1.0 | Prisma mocking | +| babel-plugin-react-compiler | 1.0.0 | React Compiler (Next.js 16) | +| tsx | ^4.20.6 | TypeScript execution | +| @redocly/cli | ^2.0.0 | OpenAPI linting (script only) | + +### 2.2 Unused Dev Dependencies + +| Package | Version | Import Count | Reason | +|---------|---------|-------------|--------| +| **baseline-browser-mapping** | ^2.10.0 | **0** | No imports, no script usage found | +| **tw-animate-css** | ^1.4.0 | **0** | Not imported or referenced in CSS/config | +| **@testing-library/dom** | ^10.4.1 | **0** | Not directly imported (peer of @testing-library/react) | +| **@testing-library/user-event** | ^14.6.1 | **0** | Not imported in any test file | + +--- + +## 3. Overrides Section Analysis + +```json +"overrides": { + "next-auth": { "next": "^16.0.7", "nodemailer": "^8.0.4" }, + "@auth/core": "^0.41.1", + "minimatch": "^10.2.3", + "lodash": "4.17.23", + "hono": "4.12.7", + "@hono/node-server": "1.19.11", + "serialize-javascript": "7.0.4", + "dompurify": "3.3.2", + "effect": "3.21.0", + "handlebars": "^4.7.9" +} +``` + +| Override | Purpose | Concern | +|----------|---------|---------| +| next-auth → next ^16 | Compatibility with Next.js 16 | Valid — next-auth v4 doesn't officially support Next.js 16 | +| minimatch, lodash, serialize-javascript, dompurify | Security patches | Valid — pinned to secure versions | +| hono, @hono/node-server | Forced versions | **Suspicious** — Hono is not a direct dependency, likely transitive | +| effect | Forced version | **Suspicious** — Effect is not a direct dependency | +| handlebars | Security patch | Valid | + +--- + +## 4. Bundle Size Concerns + +| Package | Approx. Size | Notes | +|---------|-------------|-------| +| @monaco-editor/react | ~5MB | Heavy — only used in storefront CSS editor | +| swagger-ui-dist | ~3MB | Heavy — only used in API docs page | +| @react-pdf/renderer | ~1MB | Moderate — invoice generation | +| recharts | ~500KB | Moderate — charts dashboard | +| @elastic/elasticsearch | ~300KB | Dynamic import — not in main bundle | + +**Recommendation:** Use `next/dynamic` with `ssr: false` for Monaco Editor and Swagger UI to prevent them from inflating the initial bundle. Both are already dynamically imported, which is good practice. + +--- + +## 5. Security Audit Summary + +``` +3 low severity vulnerabilities found +``` + +The 3 low-severity vulnerabilities should be reviewed with `npm audit` and patched if possible without breaking changes. diff --git a/docs/cursor/review/04-ROUTE-CROSS-VALIDATION.md b/docs/cursor/review/04-ROUTE-CROSS-VALIDATION.md new file mode 100644 index 00000000..b3273c31 --- /dev/null +++ b/docs/cursor/review/04-ROUTE-CROSS-VALIDATION.md @@ -0,0 +1,220 @@ +# StormCom — Route Cross-Validation Report + +**Build Date:** 2026-04-01 +**Build Status:** SUCCESS +**Total Routes (Build Output):** 402 (API + Page routes) +**API Route Files:** 291 `route.ts` +**Page Route Files:** 111 pages + +--- + +## 1. Build Output vs Documentation Cross-Validation + +### 1.1 Comparison with `docs/cursor/general/all-routes.md` + +The existing documentation at `docs/cursor/general/all-routes.md` lists 402 routes matching the build output. + +**Result: MATCH** — The documentation is current and accurate. + +### 1.2 Comparison with `docs/cursor/api-routes.md` + +The existing `docs/cursor/api-routes.md` claims 291 route modules. + +**Verification:** Counting `route.ts` files in `src/app/api/`: +``` +find src/app/api -name 'route.ts' | wc -l +→ 291 +``` + +**Result: MATCH** — The documentation accurately reflects the codebase. + +### 1.3 Comparison with `docs/cursor/nav-permissions.md` + +The navigation permissions document maps sidebar items to permission checks. + +**Cross-validation findings:** + +| Issue | Details | +|-------|---------| +| **OK** | All sidebar routes in nav-permissions.md exist in the codebase | +| **OK** | Permission strings match `src/lib/permissions.ts` definitions | +| **MINOR** | Some merchant routes listed as "outside sidebar" lack permission documentation | + +--- + +## 2. Route Classification + +### 2.1 Static Routes (○ — prerendered) + +| Route | Type | Description | +|-------|------|-------------| +| `/` | Landing | Homepage | +| `/_not-found` | Error | 404 page | +| `/api-docs` | Docs | Swagger UI viewer | +| `/checkout` | Commerce | Checkout page | +| `/checkout/confirmation` | Commerce | Order confirmation | +| `/checkout/failure` | Commerce | Payment failure | +| `/checkout/success` | Commerce | Payment success | +| `/dashboard/integrations/pathao` | Dashboard | Pathao integration (static config page) | +| `/dashboard/settings/payments` | Dashboard | Payment settings | +| `/dashboard/settings/payments/transactions` | Dashboard | Transaction history | +| `/forgot-password` | Auth | Password reset | +| `/login` | Auth | Login page | +| `/onboarding` | Auth | New user onboarding | +| `/payment/cancelled` | Commerce | Payment cancelled | +| `/payment/error` | Commerce | Payment error | +| `/payment/success` | Commerce | Payment success | +| `/pending-approval` | Auth | Account pending approval | +| `/settings/billing` | Settings | Billing page | +| `/signup` | Auth | Registration | +| `/track` | Tracking | Order tracking form | +| `/verify-email` | Auth | Email verification | + +**Total Static:** 21 routes + +### 2.2 Dynamic Routes (ƒ — server-rendered) + +#### Auth & Account (5 routes) +- `/login`, `/signup`, `/forgot-password`, `/verify-email`, `/pending-approval` (some static) + +#### Super Admin Panel (18 routes) +| Route | Description | +|-------|-------------| +| `/admin` | Admin dashboard | +| `/admin/activity` | Platform activity log | +| `/admin/analytics` | Platform analytics | +| `/admin/metrics` | System metrics | +| `/admin/notifications` | Admin notifications | +| `/admin/organizations` | Organization management | +| `/admin/roles/requests` | Role request queue | +| `/admin/roles/requests/[id]` | Role request detail | +| `/admin/settings` | Platform settings | +| `/admin/setup-payment` | Payment gateway setup | +| `/admin/stores` | Store list | +| `/admin/stores/[id]` | Store detail | +| `/admin/stores/create` | Create store | +| `/admin/stores/requests` | Store requests | +| `/admin/users` | User management | +| `/admin/users/[id]` | User detail | +| `/admin/users/pending` | Pending approvals | + +#### Merchant Dashboard (45 routes) +| Group | Route Count | Key Routes | +|-------|-------------|------------| +| Dashboard Home | 1 | `/dashboard` | +| Products | 4 | `/dashboard/products`, `new`, `[id]` | +| Categories | 3 | `/dashboard/categories`, `new`, `[slug]` | +| Brands | 3 | `/dashboard/brands`, `new`, `[slug]` | +| Attributes | 3 | `/dashboard/attributes`, `new`, `[id]` | +| Inventory | 1 | `/dashboard/inventory` | +| Reviews | 1 | `/dashboard/reviews` | +| Orders | 3 | `/dashboard/orders`, `[id]`, `cod` | +| Customers | 1 | `/dashboard/customers` | +| Analytics | 1 | `/dashboard/analytics` | +| Stores | 1 | `/dashboard/stores` | +| Store Settings | 8 | `appearance`, `editor`, `roles`, `request`, `settings`, `shipping`, `shipments`, `staff` | +| Subscriptions | 2 | `/dashboard/subscriptions`, `success` | +| Marketing | 6 | `coupons`, `emails`, `landing-pages` (4 sub-routes) | +| Integrations | 3 | Facebook, Pathao, main | +| Other | 4 | `cart`, `visual-editor`, `webhooks`, `notifications` | +| Admin (sub) | 2 | `admin`, `admin/subscriptions` | + +#### Public Storefront (13 routes) +| Route | Description | +|-------|-------------| +| `/store/[slug]` | Store homepage | +| `/store/[slug]/products` | Product listing | +| `/store/[slug]/products/[productSlug]` | Product detail | +| `/store/[slug]/categories` | Category listing | +| `/store/[slug]/categories/[categorySlug]` | Category products | +| `/store/[slug]/cart` | Shopping cart | +| `/store/[slug]/checkout` | Store checkout | +| `/store/[slug]/checkout/success` | Checkout success | +| `/store/[slug]/checkout/failure` | Checkout failure | +| `/store/[slug]/checkout/cancel` | Checkout cancelled | +| `/store/[slug]/orders/track` | Order tracking | +| `/store/[slug]/orders/view` | Order view | + +#### Settings (5 routes) +- `/settings`, `/settings/ai`, `/settings/api-tokens`, `/settings/billing`, `/settings/integrations/facebook` + +#### Other (12 routes) +- `/chat`, `/stormpilot`, `/team`, `/projects`, `/store-not-found` +- `/lp/[storeSlug]/[pageSlug]`, `/lp/preview/[templateId]` +- `/track/[consignmentId]`, `/track/order/[orderId]` +- `/dashboard/store-request` + +--- + +## 3. API Routes by Domain + +### 3.1 Route Count by Prefix + +| Prefix | Count | Methods | +|--------|-------|---------| +| `/api/admin/*` | 35 | GET, POST, PUT, PATCH, DELETE | +| `/api/chat/*` | 28 | GET, POST, PUT, DELETE | +| `/api/integrations/facebook/*` | 22 | GET, POST, PUT, DELETE | +| `/api/stores/[id]/*` | 22 | GET, POST, PUT, PATCH, DELETE | +| `/api/subscriptions/*` | 18 | GET, POST, PUT | +| `/api/shipping/pathao/*` | 16 | GET, POST | +| `/api/orders/*` | 16 | GET, POST, PUT, PATCH | +| `/api/analytics/*` | 15 | GET, POST, PUT, DELETE | +| `/api/webhooks/*` | 10 | GET, POST, PUT, DELETE | +| `/api/products/*` | 10 | GET, POST, PUT, PATCH, DELETE | +| `/api/store/[slug]/*` | 9 | GET, POST | +| `/api/payments/*` | 7 | GET, POST, PUT | +| `/api/landing-pages/*` | 6 | GET, POST, PUT, DELETE | +| `/api/notifications/*` | 6 | GET, PUT, POST | +| `/api/inventory/*` | 6 | GET, POST, PUT | +| `/api/checkout/*` | 4 | POST | +| `/api/customers/*` | 4 | GET, POST, PUT, DELETE | +| `/api/cart/*` | 4 | GET, POST, PUT, DELETE | +| `/api/v1/*` | 4 | GET, POST | +| Other singletons | ~40 | Various | + +### 3.2 Unauthenticated Endpoints + +Routes that accept requests without authentication: + +| Route | Risk Level | Purpose | +|-------|-----------|---------| +| `/api/auth/[...nextauth]` | Low | NextAuth handler | +| `/api/auth/signup` | Low | Registration | +| `/api/auth/verify-email` | Low | Email verification | +| `/api/health` | Low | Health check | +| `/api/health/redis` | **Medium** | Exposes Redis connectivity | +| `/api/store/[slug]` | Low | Public store info | +| `/api/store/[slug]/payment-methods` | Low | Available payment methods | +| `/api/store/[slug]/orders` | **Medium** | Guest order creation | +| `/api/store/[slug]/orders/[orderId]` | **High** | Order details by ID | +| `/api/store/[slug]/orders/[orderId]/verify-payment` | **Critical** | Payment verification | +| `/api/store/[slug]/orders/track` | Low | Order tracking | +| `/api/store/[slug]/cart/validate` | Low | Cart validation | +| `/api/store/[slug]/coupons/validate` | Low | Coupon validation | +| `/api/webhooks/stripe` | Low | Stripe webhook | +| `/api/webhooks/facebook` | Low | Facebook webhook | +| `/api/webhooks/pathao` | Low | Pathao webhook | +| `/api/webhooks/sslcommerz/*` | Low | SSLCommerz callbacks | +| `/api/admin/setup-payment-configs` | **Critical** | Auth commented out | +| `/api/openapi` | Low | API spec | +| `/api/csrf-token` | Low | CSRF token endpoint | +| `/api/subscription-plans` | Low | Public plan listing | +| `/api/tracking` | Low | Order tracking | +| `/api/demo/create-store` | **High** | Demo store creation | + +--- + +## 4. Discrepancies Found + +### 4.1 Routes in Code but Missing from API Documentation + +| Route | Status | +|-------|--------| +| All routes present | Documentation is comprehensive | + +### 4.2 Documentation Notes + +- `docs/cursor/api-routes.md` includes a PowerShell regeneration script — should also include bash/Linux equivalent +- The API docs page at `/api-docs` loads Swagger UI from the `/api/openapi` endpoint — functional +- No versioned API documentation exists (only v1 routes for health, models, products, chat) diff --git a/docs/cursor/review/05-SECURITY-VULNERABILITIES.md b/docs/cursor/review/05-SECURITY-VULNERABILITIES.md new file mode 100644 index 00000000..fd91547d --- /dev/null +++ b/docs/cursor/review/05-SECURITY-VULNERABILITIES.md @@ -0,0 +1,208 @@ +# StormCom — Security Vulnerabilities & Issues Report + +**Audit Date:** 2026-04-01 +**Severity Distribution:** 10 Critical, 16 High, 28 Medium, 12 Low +**Total Findings:** 66 + +--- + +## Severity Legend + +| Level | Definition | +|-------|-----------| +| **CRITICAL** | Immediate exploitation risk — data breach, unauthorized access, financial loss | +| **HIGH** | Significant security weakness requiring prompt remediation | +| **MEDIUM** | Security concern that should be addressed in next sprint | +| **LOW** | Minor improvement or defense-in-depth enhancement | + +--- + +## 1. CRITICAL Findings (10) + +### C-01: SSRF in Webhook Delivery +- **File:** `src/lib/webhook-delivery.ts` (Lines 121-127) +- **Description:** User-provided webhook URLs are fetched via `fetch()` without any URL validation. Attackers can set webhook URLs to internal services (AWS metadata at `169.254.169.254`, localhost APIs, or internal network resources). +- **Impact:** Internal network reconnaissance, AWS credential theft, internal API abuse +- **Fix:** Validate URLs against an allowlist. Reject private IPs, localhost, link-local addresses, and non-HTTP(S) protocols. Use a URL validation library with SSRF protection. + +### C-02: Unauthenticated Payment Verification +- **File:** `src/app/api/store/[slug]/orders/[orderId]/verify-payment/route.ts` +- **Description:** Any unauthenticated caller can trigger payment verification and potentially mark orders as paid. +- **Impact:** Financial fraud — orders marked as paid without actual payment +- **Fix:** Require authentication or a signed/time-limited verification token tied to the payment session. + +### C-03: Authentication Disabled on Payment Config +- **File:** `src/app/api/admin/setup-payment-configs/route.ts` +- **Description:** Authentication is entirely commented out. Anonymous users can inject SSLCommerz payment configurations into every organization. Hardcoded test credentials are present in source code. +- **Impact:** Payment gateway hijacking, credential exposure +- **Fix:** Restore authentication. Remove hardcoded credentials. Use environment variables. + +### C-04: Order PII Exposure +- **File:** `src/app/api/store/[slug]/orders/[orderId]/route.ts` +- **Description:** Full order details including customer PII (name, email, phone, addresses), payment attempts, and pricing are exposed to any unauthenticated caller who knows an order ID. +- **Impact:** Mass PII harvesting by enumeration of order IDs +- **Fix:** Require authentication or email/phone verification. Add rate limiting. + +### C-05: Database-Based Rate Limiting +- **File:** `src/lib/rate-limiter.ts` (Lines 96-191) +- **Description:** Rate limiting that performs DELETE + SELECT + INSERT/UPDATE on the primary database for every API request. Creates write amplification, lock contention, and potential deadlocks. +- **Impact:** Database performance degradation under load, potential DoS amplification +- **Fix:** Replace with Redis-based rate limiting. Remove the database-backed implementation. + +### C-06: Environment Crash on Import +- **File:** `src/lib/env.ts` (Line 51) +- **Description:** `validateEnv()` runs at module import time. Any file importing `env.ts` crashes the entire application if required environment variables are missing — including during build time and testing. +- **Impact:** Build failures, test failures, deployment instability +- **Fix:** Make validation lazy with a getter function pattern. + +### C-07: AES-CBC Without Authentication +- **File:** `src/lib/encryption.ts` (Line 16) +- **Description:** Uses `aes-256-cbc` which provides confidentiality but not integrity. Vulnerable to bit-flipping attacks and padding oracle attacks. +- **Impact:** Encrypted data can be modified without detection (e.g., Pathao API credentials) +- **Fix:** Switch to `aes-256-gcm` which includes an authentication tag. + +### C-08: Unlimited Trial Creation +- **File:** `src/app/api/subscriptions/init-trial/route.ts` +- **Description:** Production guard relies solely on `NODE_ENV` string comparison. Misconfiguration allows any authenticated user to create unlimited trial subscriptions. +- **Impact:** Revenue loss from unlimited free trials +- **Fix:** Add server-side check for existing trials per store. Rate limit the endpoint. + +### C-09: Tenant Isolation Leak in Attribute Service +- **File:** `src/lib/services/attribute.service.ts` +- **Description:** Queries missing `storeId` filter allow cross-tenant attribute access. +- **Impact:** Data leakage between tenants +- **Fix:** Add `storeId` filter to all attribute queries. + +### C-10: Non-Functional Payment Providers +- **Files:** `src/lib/payments/providers/bkash.service.ts`, `nagad.service.ts` +- **Description:** bKash and Nagad payment provider classes are skeleton/stub code. Payment persistence is non-functional. +- **Impact:** Failed payment processing for users selecting these methods +- **Fix:** Complete implementation or remove from available payment options. + +--- + +## 2. HIGH Findings (16) + +| ID | Finding | File | Impact | +|----|---------|------|--------| +| H-01 | Mass assignment in product CRUD — raw body passed to Prisma | API product routes | Data corruption, privilege escalation | +| H-02 | Missing store access verification on SSLCommerz payment initiation | payments/sslcommerz/initiate | Payment against any store | +| H-03 | Nagad callback lacks amount verification | payments/nagad/callback | Incorrect payment confirmation | +| H-04 | Timing-unsafe Facebook webhook signature comparison | webhooks/facebook | Signature bypass via timing attack | +| H-05 | No permission check on subscription creation | subscriptions/subscribe | Any role can subscribe | +| H-06 | IDOR on unauthenticated order GET | orders/[id] | Order data enumeration | +| H-07 | `constantTimeCompare` early-returns on length mismatch | security.ts:139 | Token/signature comparison bypass | +| H-08 | Three duplicate rate-limiting systems | Multiple files | Inconsistent protection | +| H-09 | Account status not rechecked on JWT refresh | auth.ts:162 | Suspended user access | +| H-10 | Unbounded org/tenant queries | multi-tenancy.ts:112, tenant-resolver.ts:117 | DoS via query amplification | +| H-11 | `KEYS` command in cache invalidation | cache.ts:352 | Redis blocking/DoS | +| H-12 | `setTimeout` retries in serverless | webhook-delivery.ts:282 | Lost webhook deliveries | +| H-13 | Internal error details leaked in 500 responses | error-handler.ts:82 | Information disclosure | +| H-14 | No email rate limiting | email-service.ts | Email quota abuse | +| H-15 | Static bearer token for admin endpoint | admin/fix-broken-trials | Hardcoded credential | +| H-16 | Four inconsistent session-fetching approaches | Multiple files | Duplicate DB queries | + +--- + +## 3. MEDIUM Findings (28) + +| ID | Category | Finding | Location | +|----|----------|---------|----------| +| M-01 | Auth | Magic link URL logged (contains auth token) | auth.ts:46 | +| M-02 | Auth | `parseInt` without `isNaN` check | auth.ts:33 | +| M-03 | Multi-tenant | Race condition in `ensureUniqueSlug` | multi-tenancy.ts:144 | +| M-04 | Multi-tenant | No Row-Level Security at database level | Schema-wide | +| M-05 | API | Permission string leaked in error messages | api-middleware.ts:332 | +| M-06 | API | Content-Type check blocks file uploads | api-middleware.ts:461 | +| M-07 | Security | SQL injection regex too aggressive (rejects quotes) | security.ts:231 | +| M-08 | Security | Token generation modular bias | security.ts:155 | +| M-09 | CSRF | Token not tied to session (double-submit without signing) | csrf.ts:40 | +| M-10 | CSRF | `__Host-` cookie non-functional in dev | csrf.ts:17 | +| M-11 | Rate limit | Serverless in-memory fallback useless | security/rate-limit.ts:48 | +| M-12 | Rate limit | Fail-open on Redis error | rate-limit.ts:139 | +| M-13 | Rate limit | Memory leak in InMemoryRateLimitStore | security/rate-limit.ts:92 | +| M-14 | Encryption | Padding oracle vulnerability | encryption.ts:64 | +| M-15 | Redis | Credentials may leak in error logs | redis.ts:174 | +| M-16 | Redis | Missing connection timeouts | redis.ts:191 | +| M-17 | Cache | Cache stampede (no locking) | cache.ts:171 | +| M-18 | Cache | `null` values not cacheable | cache.ts:128 | +| M-19 | Cache | Mixed in-memory/Redis stats | cache.ts:78 | +| M-20 | Tenant | Error messages leak store IDs | tenant-resolver.ts:172 | +| M-21 | Tenant | Double session fetch | tenant-resolver.ts:376 | +| M-22 | Error | Prisma errors leak column names | error-handler.ts:114 | +| M-23 | Money | No integer validation on inputs | money.ts:99 | +| M-24 | Email | No HTML escaping in templates | email-service.ts:68 | +| M-25 | Webhook | Event matching uses `contains` (false positives) | webhook-delivery.ts:351 | +| M-26 | Schema | JSON stored as `String` type | schema.prisma (multiple) | +| M-27 | Config | CSP uses `unsafe-eval` + `unsafe-inline` | next.config.ts:159 | +| M-28 | Config | `ignoreBuildErrors: true` hides type errors | next.config.ts:13 | + +--- + +## 4. LOW Findings (12) + +| ID | Finding | Location | +|----|---------|----------| +| L-01 | Dynamic import in JWT callback hot path | auth.ts:246 | +| L-02 | Verbose query logging in dev | prisma.ts:20 | +| L-03 | Hardcoded role lists (no compile-time safety) | permissions.ts:370 | +| L-04 | `sortOrder` cast bypasses validation | api-middleware.ts:607 | +| L-05 | CUID regex rejects CUID2 | security.ts:71 | +| L-06 | Regex `/g` flag state bugs | xss-protection.ts:432, security.ts:231 | +| L-07 | Hardcoded currency factor | money.ts:29 | +| L-08 | Hardcoded production domains | email-service.ts:29 | +| L-09 | `.bak` file in components | landing-page-editor-client.tsx.bak | +| L-10 | Duplicate component files | product-quick-view.tsx (2 copies) | +| L-11 | `sanitizeInt` doesn't handle `Infinity` | input-sanitizer.ts:159 | +| L-12 | Stateful regex in `containsDangerousContent` | xss-protection.ts:432 | + +--- + +## 5. Architectural Security Issues + +### 5.1 Multi-Tenancy Isolation + +**Current Approach:** Application-level `storeId` filtering in queries +**Risk:** A single missed `WHERE storeId = ?` clause leaks data across tenants +**Recommendation:** Implement PostgreSQL Row-Level Security (RLS) as a database-level safety net + +### 5.2 Secret Management + +| Concern | Current | Recommended | +|---------|---------|-------------| +| Pathao credentials | Stored in `Store` model (plain text) | Use encrypted vault or env vars | +| Facebook access tokens | Stored in `FacebookIntegration` | Encrypt at rest | +| API keys | Hashed in `ApiToken` | Good — hash is correct approach | +| Payment gateway config | `Json` field on `PaymentConfiguration` | Encrypt sensitive fields | + +### 5.3 CSP Policy Gaps + +Current CSP allows: +- `unsafe-eval` — enables eval()-based attacks +- `unsafe-inline` — enables inline script injection +- Broad `connect-src` to `*.vercel.app` and `*.upstash.io` + +**Recommendation:** Use nonces for inline scripts, remove `unsafe-eval`, and restrict `connect-src` to specific domains. + +--- + +## 6. Remediation Priority + +### Immediate (Block deployment) +1. C-02: Unauthenticated payment verification +2. C-03: Auth disabled on payment config +3. C-04: Order PII exposure +4. C-01: SSRF in webhooks + +### Next Sprint +5. C-07: Switch to AES-GCM +6. C-05: Replace DB rate limiting with Redis +7. H-01: Fix mass assignment +8. H-07: Fix `constantTimeCompare` +9. H-13: Sanitize error responses in production + +### Scheduled +10. M-04: Implement RLS +11. H-08: Consolidate rate limiting +12. H-16: Unify session management +13. M-27: Harden CSP policy diff --git a/docs/cursor/review/06-TRACEABILITY-MATRIX.md b/docs/cursor/review/06-TRACEABILITY-MATRIX.md new file mode 100644 index 00000000..f7f1e3c9 --- /dev/null +++ b/docs/cursor/review/06-TRACEABILITY-MATRIX.md @@ -0,0 +1,192 @@ +# StormCom — Requirements Traceability Matrix + +**Project:** StormCom Multitenant E-commerce SaaS Platform +**Date:** 2026-04-01 +**Methodology:** Forward + Backward traceability mapping requirements to implementation, API routes, database models, UI pages, and tests. + +--- + +## 1. Functional Requirements Traceability + +### FR-01: User Authentication & Authorization + +| Req ID | Requirement | API Routes | DB Models | UI Pages | Lib Files | Test Coverage | +|--------|-------------|------------|-----------|----------|-----------|---------------| +| FR-01.1 | Email/password signup | `/api/auth/signup` | User, PendingSignup | `/signup` | auth.ts, email-service.ts | auth.test.ts | +| FR-01.2 | Email verification | `/api/auth/verify-email` | VerificationToken | `/verify-email` | auth.ts | auth.test.ts | +| FR-01.3 | Magic link login | `/api/auth/[...nextauth]` | Session, Account | `/login` | auth.ts | Partial | +| FR-01.4 | Password-based login | `/api/auth/[...nextauth]` | User (passwordHash) | `/login` | auth.ts, bcryptjs | auth.test.ts | +| FR-01.5 | Account approval flow | `/api/admin/users/[id]/approve` | User (accountStatus) | `/admin/users`, `/pending-approval` | — | None | +| FR-01.6 | Account suspension | `/api/admin/users/[id]/suspend` | User (accountStatus) | `/admin/users/[id]` | — | None | +| FR-01.7 | Role-based permissions | `/api/permissions` | StoreStaff, Membership | Dashboard sidebar | permissions.ts, store-permissions.ts | None | +| FR-01.8 | Custom roles | `/api/stores/[id]/custom-roles` | CustomRole, CustomRoleRequest | Roles pages | custom-role-permissions.ts | None | +| FR-01.9 | API token management | `/api/api-tokens`, `/api/api-tokens/[id]` | ApiToken | `/settings/api-tokens` | api-token.ts | None | +| FR-01.10 | CSRF protection | `/api/csrf-token` | — | — | csrf.ts, security/csrf.ts | None | + +### FR-02: Store Management + +| Req ID | Requirement | API Routes | DB Models | UI Pages | Lib Files | Test Coverage | +|--------|-------------|------------|-----------|----------|-----------|---------------| +| FR-02.1 | Create store | `/api/stores` POST | Store, Organization | `/dashboard/stores` | store.service.ts | stores.test.ts | +| FR-02.2 | Store settings | `/api/stores/[id]/settings` | Store | `stores/[storeId]/settings` | store.service.ts | stores.test.ts | +| FR-02.3 | Store staff management | `/api/stores/[id]/staff` | StoreStaff | `stores/[storeId]/staff` | — | None | +| FR-02.4 | Store request approval | `/api/store-requests`, `/api/admin/store-requests` | StoreRequest | `/dashboard/store-request`, `/admin/stores/requests` | — | None | +| FR-02.5 | Custom domain | `/api/stores/[id]/domain` | Store (customDomain) | `stores/[storeId]/settings` | subdomain.ts | None | +| FR-02.6 | PWA support | `/api/stores/[id]/pwa`, `/api/stores/[id]/manifest`, `/api/stores/[id]/sw` | Store (pwaEnabled) | Appearance page | pwa components | None | +| FR-02.7 | Storefront customization | `/api/stores/[id]/storefront`, `/api/stores/[id]/storefront/draft`, `/api/stores/[id]/storefront/publish` | Store (storefrontConfig) | Appearance editor | storefront/* | None | +| FR-02.8 | Theme management | `/api/stores/[id]/theme`, `/api/themes` | Store | Appearance page | storefront/theme-templates.ts | None | + +### FR-03: Product Management + +| Req ID | Requirement | API Routes | DB Models | UI Pages | Lib Files | Test Coverage | +|--------|-------------|------------|-----------|----------|-----------|---------------| +| FR-03.1 | CRUD products | `/api/products`, `/api/products/[id]` | Product, ProductVariant | Products pages | product.service.ts | products.test.ts | +| FR-03.2 | Product variants | `/api/products/[id]` | ProductVariant | Product edit form | product.service.ts | products.test.ts | +| FR-03.3 | Product attributes | `/api/attributes`, `/api/product-attributes` | ProductAttribute, ProductAttributeValue | Attributes pages | attribute.service.ts | None | +| FR-03.4 | Category management | `/api/categories`, `/api/categories/[slug]`, `/api/categories/tree` | Category | Categories pages | category.service.ts | None | +| FR-03.5 | Brand management | `/api/brands`, `/api/brands/[slug]` | Brand | Brands pages | brand.service.ts | None | +| FR-03.6 | Product images | `/api/media/upload`, `/api/products/upload` | Product (images) | Product edit | storage.ts | None | +| FR-03.7 | Bulk import/export | `/api/products/import`, `/api/products/export`, `/api/products/bulk` | Product | Products page | papaparse | None | +| FR-03.8 | Product reviews | `/api/reviews`, `/api/products/[id]/reviews` | Review | Reviews page | review.service.ts | None | +| FR-03.9 | Product discounts | `/api/products/[id]` | Product (discountType, discountValue) | Product edit | discount-utils.ts | None | + +### FR-04: Order Management + +| Req ID | Requirement | API Routes | DB Models | UI Pages | Lib Files | Test Coverage | +|--------|-------------|------------|-----------|----------|-----------|---------------| +| FR-04.1 | Order creation | `/api/orders` POST, `/api/store/[slug]/orders` POST | Order, OrderItem | Checkout flow | order.service.ts, order-processing.service.ts | orders.test.ts | +| FR-04.2 | Order listing | `/api/orders` GET | Order | `/dashboard/orders` | order.service.ts | orders.test.ts | +| FR-04.3 | Order detail | `/api/orders/[id]` | Order, OrderItem | `/dashboard/orders/[id]` | order.service.ts | orders.test.ts | +| FR-04.4 | Status updates | `/api/orders/[id]/status` | Order (status) | Order detail | order.service.ts | None | +| FR-04.5 | Order cancellation | `/api/orders/[id]/cancel` | Order (canceledAt) | Order detail | order.service.ts | None | +| FR-04.6 | Refund processing | `/api/orders/[id]/refund` | Order (refundedAmount) | Order detail | order.service.ts | None | +| FR-04.7 | Invoice generation | `/api/orders/[id]/invoice` | Order | Order detail | @react-pdf/renderer | None | +| FR-04.8 | Fulfillment | `/api/orders/[id]/fulfillments`, `/api/fulfillments/[id]` | Fulfillment | Order detail | — | None | +| FR-04.9 | Bulk operations | `/api/orders/bulk`, `/api/orders/export` | Order | Orders page | — | None | +| FR-04.10 | COD verification | `/api/orders/cod/verify` | Order | `/dashboard/orders/cod` | — | None | +| FR-04.11 | Order tracking | `/api/orders/track`, `/api/store/[slug]/orders/track` | Order | `/track/*` pages | — | None | +| FR-04.12 | Real-time updates | `/api/orders/stream` | — | Orders page | SSE | None | + +### FR-05: Checkout & Payments + +| Req ID | Requirement | API Routes | DB Models | UI Pages | Lib Files | Test Coverage | +|--------|-------------|------------|-----------|----------|-----------|---------------| +| FR-05.1 | Cart management | `/api/cart`, `/api/cart/[id]`, `/api/cart/count`, `/api/cart/validate` | — (client-side) | Cart pages | cart-store.ts | None | +| FR-05.2 | Checkout validation | `/api/checkout/validate` | — | Checkout page | checkout.service.ts | None | +| FR-05.3 | Shipping calculation | `/api/checkout/shipping` | — | Checkout page | checkout.service.ts | None | +| FR-05.4 | Payment intent | `/api/checkout/payment-intent` | PaymentAttempt | Checkout page | payment-orchestrator.ts | None | +| FR-05.5 | Checkout completion | `/api/checkout/complete` | Order | Success page | checkout.service.ts | None | +| FR-05.6 | Stripe integration | `/api/webhooks/stripe` | PaymentConfiguration | Payment settings | stripe.service.ts | None | +| FR-05.7 | SSLCommerz integration | `/api/payments/sslcommerz/initiate`, `/api/webhooks/sslcommerz/*` | PaymentConfiguration | Payment settings | sslcommerz.service.ts | None | +| FR-05.8 | bKash/Nagad (stub) | `/api/payments/bkash/callback`, `/api/payments/nagad/callback` | PaymentConfiguration | — | bkash.service.ts, nagad.service.ts | None | +| FR-05.9 | Coupon application | `/api/coupons`, `/api/coupons/validate` | DiscountCode | Coupons page | discount.service.ts | None | + +### FR-06: Inventory Management + +| Req ID | Requirement | API Routes | DB Models | UI Pages | Lib Files | Test Coverage | +|--------|-------------|------------|-----------|----------|-----------|---------------| +| FR-06.1 | Inventory tracking | `/api/inventory` | Product, ProductVariant, InventoryLog | `/dashboard/inventory` | inventory.service.ts | inventory.test.ts | +| FR-06.2 | Stock adjustment | `/api/inventory/adjust` | InventoryLog | Inventory page | inventory.service.ts | inventory.test.ts | +| FR-06.3 | Bulk operations | `/api/inventory/bulk` | InventoryLog | Inventory page | — | None | +| FR-06.4 | Low stock alerts | `/api/inventory/low-stock` | Product | Inventory widget | inventory.service.ts | None | +| FR-06.5 | Inventory reservation | `/api/cron/release-reservations` | InventoryReservation, InventoryReservationItem | — | reservation.service.ts | None | +| FR-06.6 | History/audit | `/api/inventory/history`, `/api/inventory/export` | InventoryLog | Inventory page | inventory.service.ts | None | + +### FR-07: Subscription & Billing + +| Req ID | Requirement | API Routes | DB Models | UI Pages | Lib Files | Test Coverage | +|--------|-------------|------------|-----------|----------|-----------|---------------| +| FR-07.1 | Plan management | `/api/admin/plans`, `/api/subscription-plans`, `/api/subscriptions/plans` | SubscriptionPlanModel | Admin subscriptions | subscription/* | None | +| FR-07.2 | Trial initialization | `/api/subscriptions/init-trial` | Subscription | Dashboard | subscription/init.ts | None | +| FR-07.3 | Subscribe/upgrade/downgrade | `/api/subscriptions/subscribe`, `upgrade`, `downgrade` | Subscription, SubscriptionLog | Subscriptions page | state-machine.ts, billing-service.ts | None | +| FR-07.4 | Cancellation | `/api/subscriptions/cancel` | Subscription | Cancel dialog | subscription/* | None | +| FR-07.5 | Renewal | `/api/subscriptions/renew` | Subscription, SubPayment | Renewal modal | subscription/* | None | +| FR-07.6 | Grace period | `/api/subscription/grace-period-status`, `extend-grace-period` | Subscription (graceEndsAt) | Grace guard | subscription/* | None | +| FR-07.7 | Billing history | `/api/billing/history` | Invoice, SubPayment | `/settings/billing` | billing-service.ts | None | +| FR-07.8 | Feature enforcement | — | SubscriptionPlanModel | Global enforcer | feature-enforcer.ts | None | +| FR-07.9 | SSLCommerz subscription payment | `/api/subscriptions/sslcommerz/*` | SubPayment | — | payment-gateway.ts | None | + +### FR-08: Analytics & Reporting + +| Req ID | Requirement | API Routes | DB Models | UI Pages | Lib Files | Test Coverage | +|--------|-------------|------------|-----------|----------|-----------|---------------| +| FR-08.1 | Dashboard analytics | `/api/analytics/dashboard` | — (aggregation) | `/dashboard/analytics` | analytics-dashboard.service.ts | analytics-dashboard.service.test.ts | +| FR-08.2 | Revenue analytics | `/api/analytics/revenue` | Order | Analytics page | analytics.service.ts | None | +| FR-08.3 | Sales analytics | `/api/analytics/sales` | Order | Analytics page | analytics.service.ts | None | +| FR-08.4 | Customer analytics | `/api/analytics/customers` | Customer | Analytics page | analytics.service.ts | None | +| FR-08.5 | Top products | `/api/analytics/products/top` | OrderItem, Product | Analytics page | analytics.service.ts | None | +| FR-08.6 | Search analytics | `/api/analytics/search`, `/api/search/analytics` | SearchAnalytics | Analytics page | search.service.ts | search.service.test.ts | +| FR-08.7 | Real-time metrics | `/api/analytics/realtime`, `realtime/stream` | — | Analytics page | — | None | +| FR-08.8 | Cache analytics | `/api/analytics/cache`, `/api/cache/stats` | CacheMetric | Analytics page | cache.ts | cache-service.test.ts | +| FR-08.9 | API usage | `/api/analytics/api-usage` | ApiUsageLog | Analytics page | — | None | +| FR-08.10 | Performance | `/api/analytics/performance`, `/api/metrics` | PerformanceMetric | Admin metrics | performance-monitor.ts | None | +| FR-08.11 | Alerts | `/api/analytics/alerts`, `alerts/[id]` | AnalyticsAlert | Analytics page | — | None | +| FR-08.12 | Export | `/api/analytics/export` | — | Analytics page | — | None | + +### FR-09: Integrations + +| Req ID | Requirement | API Routes | DB Models | UI Pages | Lib Files | Test Coverage | +|--------|-------------|------------|-----------|----------|-----------|---------------| +| FR-09.1 | Facebook OAuth | `/api/integrations/facebook/oauth/*` | FacebookIntegration, FacebookOAuthState | Integration settings | facebook/oauth-service.ts | None | +| FR-09.2 | Product sync (FB) | `/api/integrations/facebook/products/sync` | FacebookProduct | Facebook dashboard | facebook/product-sync-service.ts | None | +| FR-09.3 | Order sync (FB) | `/api/integrations/facebook/orders/*` | FacebookOrder | Facebook dashboard | facebook/order-manager.ts | None | +| FR-09.4 | Messenger | `/api/integrations/facebook/messages/*` | FacebookConversation, FacebookMessage | Messages page | facebook/messenger-service.ts | None | +| FR-09.5 | Conversion tracking | `/api/integrations/facebook/conversions` | ConversionEvent | Conversions dashboard | facebook/conversions-api.ts | None | +| FR-09.6 | Pathao shipping | `/api/shipping/pathao/*` | Store (pathao fields) | Shipping pages | pathao.service.ts | None | +| FR-09.7 | Webhooks CRUD | `/api/webhooks`, `/api/webhooks/[id]` | Webhook, WebhookDelivery | `/dashboard/webhooks` | webhook.service.ts, webhook-delivery.ts | None | + +### FR-10: AI & Chat + +| Req ID | Requirement | API Routes | DB Models | UI Pages | Lib Files | Test Coverage | +|--------|-------------|------------|-----------|----------|-----------|---------------| +| FR-10.1 | Chat interface | `/api/chat/generate`, `assistant`, `messages` | ChatMessage, ChatSession | `/chat` | ollama.ts | None | +| FR-10.2 | Session management | `/api/chat/sessions`, `sessions/[id]` | ChatSession | Chat page | chat-session.ts | None | +| FR-10.3 | Model management | `/api/chat/models/*` | OllamaConfig | Settings | ollama.ts | None | +| FR-10.4 | OpenAI-compatible API | `/api/chat/openai/v1/*` | — | — | ollama.ts | None | +| FR-10.5 | AI recommendations | `/api/ai/recommendations` | — | — | recommendation.service.ts | None | +| FR-10.6 | Semantic search | `/api/chat/semantic-search/products` | Product | — | — | None | +| FR-10.7 | Tools/Actions | `/api/chat/tools/execute`, `actions/parse` | — | — | chat-tools.ts | None | +| FR-10.8 | Usage tracking | `/api/chat/usage` | ChatUsageLog | — | — | None | + +--- + +## 2. Test Coverage Matrix + +| Area | Route Tests | Service Tests | Component Tests | E2E Tests | Overall | +|------|------------|---------------|-----------------|-----------|---------| +| Auth | ✅ auth.test.ts | — | — | — | Partial | +| Products | ✅ products.test.ts | — | — | — | Partial | +| Orders | ✅ orders.test.ts | — | — | — | Partial | +| Customers | ✅ customers.test.ts | — | — | — | Partial | +| Stores | ✅ stores.test.ts | — | — | — | Partial | +| Inventory | ✅ inventory.test.ts | — | — | — | Partial | +| API Versioning | ✅ versioning.test.ts | — | — | — | Partial | +| Analytics | — | ✅ analytics-dashboard.service.test.ts | — | — | Partial | +| Search | — | ✅ search.service.test.ts | — | — | Partial | +| Cache | — | ✅ cache-service.test.ts | — | — | Partial | +| UI Components | — | — | ✅ 8 component tests | — | Partial | +| Checkout | — | — | — | — | **None** | +| Payments | — | — | — | — | **None** | +| Subscriptions | — | — | — | — | **None** | +| Integrations | — | — | — | — | **None** | +| Admin | — | — | — | — | **None** | +| Chat/AI | — | — | — | — | **None** | + +**Overall Test Coverage:** ~15% of functional requirements have any test coverage. + +--- + +## 3. Non-Functional Requirements Traceability + +| Req ID | Requirement | Implementation | Status | +|--------|-------------|---------------|--------| +| NFR-01 | Performance monitoring | PerformanceMetric model, performance-monitor.ts, metrics API | ✅ Implemented | +| NFR-02 | Caching strategy | Redis (ioredis + Upstash), cache.ts, cache-config.ts | ✅ Implemented (with issues) | +| NFR-03 | Rate limiting | 3 implementations (DB, Redis, in-memory) | ⚠️ Needs consolidation | +| NFR-04 | Audit logging | AuditLog model, audit-logger.ts | ✅ Implemented | +| NFR-05 | GDPR compliance | `/api/gdpr/export`, `/api/gdpr/delete` | ✅ Endpoints exist | +| NFR-06 | Internationalization | i18n module (en, bn) | ⚠️ Partial (2 languages) | +| NFR-07 | Security headers | next.config.ts headers() | ⚠️ CSP needs hardening | +| NFR-08 | Multi-tenancy isolation | Application-level storeId filtering | ⚠️ No RLS | +| NFR-09 | Observability | Correlation ID middleware, structured logging | ✅ Implemented | +| NFR-10 | API versioning | v1 routes, api-versioning.ts | ⚠️ Partial (only 4 v1 routes) | diff --git a/docs/cursor/review/07-CRUD-MATRIX.md b/docs/cursor/review/07-CRUD-MATRIX.md new file mode 100644 index 00000000..339560d4 --- /dev/null +++ b/docs/cursor/review/07-CRUD-MATRIX.md @@ -0,0 +1,246 @@ +# StormCom — CRUD Operations Matrix + +**Date:** 2026-04-01 +**Purpose:** Maps Create, Read, Update, Delete operations for each database entity to their corresponding API routes, services, and UI pages. + +--- + +## Legend + +| Symbol | Meaning | +|--------|---------| +| **C** | Create | +| **R** | Read (single/list) | +| **U** | Update | +| **D** | Delete (hard or soft) | +| ✅ | Operation implemented | +| ⚠️ | Partially implemented or has issues | +| ❌ | Missing but expected | +| — | Not applicable | + +--- + +## 1. Core Commerce Entities + +### Product + +| Operation | API Route | HTTP Method | Service | UI Page | Notes | +|-----------|-----------|-------------|---------|---------|-------| +| **C** | `/api/products` | POST | product.service.ts | `/dashboard/products/new` | ✅ Full implementation | +| **R** (list) | `/api/products` | GET | product.service.ts | `/dashboard/products` | ✅ Paginated, filterable | +| **R** (single) | `/api/products/[id]` | GET | product.service.ts | `/dashboard/products/[id]` | ✅ | +| **U** | `/api/products/[id]` | PUT/PATCH | product.service.ts | `/dashboard/products/[id]` | ⚠️ Mass assignment risk | +| **D** | `/api/products/[id]` | DELETE | product.service.ts | Products page | ⚠️ Soft delete (deletedAt) | +| **C** (bulk) | `/api/products/import` | POST | — | Products page | ✅ CSV import | +| **R** (export) | `/api/products/export` | GET | — | Products page | ✅ CSV export | +| **D** (bulk) | `/api/products/bulk` | DELETE | — | Products page | ⚠️ Hard delete, no undo | +| **C** (upload) | `/api/products/upload` | POST | storage.ts | Product edit | ✅ Image upload | + +### Product Variant + +| Operation | API Route | HTTP Method | Service | Notes | +|-----------|-----------|-------------|---------|-------| +| **C** | `/api/products/[id]` | POST (nested) | product.service.ts | Created as part of product | +| **R** | `/api/products/[id]` | GET (nested) | product.service.ts | Included in product response | +| **U** | `/api/products/[id]` | PUT/PATCH (nested) | product.service.ts | Updated as part of product | +| **D** | `/api/products/[id]` | (cascade) | product.service.ts | Deleted with product | + +### Category + +| Operation | API Route | HTTP Method | Service | UI Page | Notes | +|-----------|-----------|-------------|---------|---------|-------| +| **C** | `/api/categories` | POST | category.service.ts | `/dashboard/categories/new` | ✅ | +| **R** (list) | `/api/categories` | GET | category.service.ts | `/dashboard/categories` | ✅ | +| **R** (tree) | `/api/categories/tree` | GET | category.service.ts | Category selector | ✅ | +| **R** (single) | `/api/categories/[slug]` | GET | category.service.ts | `/dashboard/categories/[slug]` | ✅ | +| **U** | `/api/categories/[slug]` | PUT/PATCH | category.service.ts | `/dashboard/categories/[slug]` | ✅ | +| **D** | `/api/categories/[slug]` | DELETE | category.service.ts | Categories page | ✅ Soft delete | + +### Brand + +| Operation | API Route | HTTP Method | Service | UI Page | Notes | +|-----------|-----------|-------------|---------|---------|-------| +| **C** | `/api/brands` | POST | brand.service.ts | `/dashboard/brands/new` | ✅ | +| **R** (list) | `/api/brands` | GET | brand.service.ts | `/dashboard/brands` | ✅ | +| **R** (single) | `/api/brands/[slug]` | GET | brand.service.ts | `/dashboard/brands/[slug]` | ✅ | +| **U** | `/api/brands/[slug]` | PUT/PATCH | brand.service.ts | `/dashboard/brands/[slug]` | ✅ | +| **D** | `/api/brands/[slug]` | DELETE | brand.service.ts | Brands page | ✅ Soft delete | + +### Order + +| Operation | API Route | HTTP Method | Service | UI Page | Notes | +|-----------|-----------|-------------|---------|---------|-------| +| **C** | `/api/orders` POST, `/api/store/[slug]/orders` POST | POST | order.service.ts, checkout.service.ts | Checkout flow | ✅ | +| **R** (list) | `/api/orders` | GET | order.service.ts | `/dashboard/orders` | ✅ Paginated, filterable | +| **R** (single) | `/api/orders/[id]` | GET | order.service.ts | `/dashboard/orders/[id]` | ⚠️ IDOR on public route | +| **U** (status) | `/api/orders/[id]/status` | PATCH | order.service.ts | Order detail | ✅ | +| **U** (cancel) | `/api/orders/[id]/cancel` | POST | order.service.ts | Order detail | ✅ | +| **U** (refund) | `/api/orders/[id]/refund` | POST | order.service.ts | Order detail | ✅ | +| **D** | — | — | — | — | ❌ No delete (soft or hard) — orders are permanent | +| **R** (export) | `/api/orders/export` | GET | — | Orders page | ✅ | +| **U** (bulk) | `/api/orders/bulk` | PATCH | — | Orders page | ✅ Bulk status update | + +### Customer + +| Operation | API Route | HTTP Method | Service | UI Page | Notes | +|-----------|-----------|-------------|---------|---------|-------| +| **C** | `/api/customers` | POST | customer.service.ts | Customers page | ✅ | +| **R** (list) | `/api/customers` | GET | customer.service.ts | `/dashboard/customers` | ✅ | +| **R** (single) | `/api/customers/[id]` | GET | customer.service.ts | Customer detail dialog | ✅ | +| **U** | `/api/customers/[id]` | PUT/PATCH | customer.service.ts | Customer edit dialog | ✅ | +| **D** | `/api/customers/[id]` | DELETE | customer.service.ts | Customer page | ✅ Soft delete | +| **R** (export) | `/api/customers/export` | GET | — | Customers page | ✅ | +| **C** (bulk) | `/api/customers/bulk` | POST | — | Customers page | ✅ | + +--- + +## 2. Store & Organization Entities + +### Store + +| Op | API Route | Method | UI Page | Notes | +|----|-----------|--------|---------|-------| +| **C** | `/api/stores` | POST | Store creation | ✅ Via store request approval | +| **R** (list) | `/api/stores` | GET | `/dashboard/stores` | ✅ | +| **R** (single) | `/api/stores/[id]` | GET | Store settings | ✅ | +| **U** | `/api/stores/[id]` | PUT/PATCH | Store settings | ✅ | +| **D** | `/api/stores/[id]` | DELETE | Stores page | ⚠️ Soft delete (deletedAt on Store) | +| **R** (public) | `/api/store/[slug]` | GET | `/store/[slug]` | ✅ Public storefront | +| **R** (lookup) | `/api/stores/lookup` | GET | — | ✅ Domain/slug lookup | + +### Organization + +| Op | API Route | Method | Notes | +|----|-----------|--------|-------| +| **C** | `/api/organizations` | POST | ✅ Created with store | +| **R** | `/api/organizations` | GET | ✅ User's orgs | +| **U** | — | — | ❌ No update endpoint | +| **D** | — | — | ❌ No delete endpoint | +| **C** (invite) | `/api/organizations/[slug]/invite` | POST | ✅ | + +### StoreStaff + +| Op | API Route | Method | Notes | +|----|-----------|--------|-------| +| **C** | `/api/stores/[id]/staff` | POST | ✅ Invite staff | +| **R** | `/api/stores/[id]/staff` | GET | ✅ List staff | +| **U** | `/api/stores/[id]/staff/[staffId]` | PATCH | ✅ Update role | +| **D** | `/api/stores/[id]/staff/[staffId]` | DELETE | ✅ Remove staff | +| **U** | `/api/stores/[id]/staff/accept-invite` | POST | ✅ Accept invite | + +--- + +## 3. Financial Entities + +### Subscription + +| Op | API Route | Method | Notes | +|----|-----------|--------|-------| +| **C** | `/api/subscriptions/subscribe` | POST | ✅ | +| **R** (current) | `/api/subscriptions/current` | GET | ✅ | +| **R** (status) | `/api/subscriptions/status` | GET | ✅ | +| **R** (list) | `/api/subscriptions` | GET | ✅ | +| **U** (upgrade) | `/api/subscriptions/upgrade` | POST | ✅ | +| **U** (downgrade) | `/api/subscriptions/downgrade` | POST | ✅ | +| **U** (cancel) | `/api/subscriptions/cancel` | POST | ✅ | +| **U** (renew) | `/api/subscriptions/renew` | POST | ✅ | +| **D** | — | — | — Not applicable (subscription states) | + +### SubscriptionPlanModel (Admin) + +| Op | API Route | Method | Notes | +|----|-----------|--------|-------| +| **C** | `/api/admin/plans` | POST | ✅ | +| **R** | `/api/admin/plans`, `/api/subscription-plans` | GET | ✅ | +| **U** | `/api/admin/plans/[id]` | PUT/PATCH | ✅ | +| **D** | `/api/admin/plans/[id]` | DELETE | ⚠️ Should soft-delete if subscriptions reference it | + +### PaymentConfiguration + +| Op | API Route | Method | Notes | +|----|-----------|--------|-------| +| **C** | `/api/payments/configurations` | POST | ⚠️ Missing auth on setup route | +| **R** | `/api/payments/configurations` | GET | ✅ | +| **U** | `/api/payments/configurations` | PUT | ✅ | +| **U** (toggle) | `/api/payments/configurations/toggle` | POST | ✅ | +| **D** | — | — | ❌ No delete endpoint | + +--- + +## 4. Integration Entities + +### FacebookIntegration + +| Op | API Route | Method | Notes | +|----|-----------|--------|-------| +| **C** | `/api/integrations/facebook/oauth/callback` | GET | ✅ Created on OAuth completion | +| **R** | `/api/integrations/facebook/status` | GET | ✅ | +| **U** | `/api/integrations/facebook/settings` | PUT | ✅ | +| **D** | `/api/integrations/facebook/disconnect` | POST | ✅ | + +### Webhook + +| Op | API Route | Method | Notes | +|----|-----------|--------|-------| +| **C** | `/api/webhooks` | POST | ✅ | +| **R** | `/api/webhooks`, `/api/webhooks/[id]` | GET | ✅ | +| **U** | `/api/webhooks/[id]` | PUT/PATCH | ✅ | +| **D** | `/api/webhooks/[id]` | DELETE | ✅ | + +--- + +## 5. Content Entities + +### LandingPage + +| Op | API Route | Method | Notes | +|----|-----------|--------|-------| +| **C** | `/api/landing-pages` | POST | ✅ | +| **R** | `/api/landing-pages`, `/api/landing-pages/[id]` | GET | ✅ | +| **U** | `/api/landing-pages/[id]` | PUT/PATCH | ✅ | +| **U** (publish) | `/api/landing-pages/[id]/publish` | POST | ✅ | +| **U** (duplicate) | `/api/landing-pages/[id]/duplicate` | POST | ✅ | +| **D** | `/api/landing-pages/[id]` | DELETE | ✅ | +| **R** (templates) | `/api/landing-pages/templates` | GET | ✅ | + +--- + +## 6. CRUD Completeness Summary + +| Entity | C | R | U | D | Complete? | +|--------|---|---|---|---|-----------| +| Product | ✅ | ✅ | ⚠️ | ⚠️ | Partial (mass assignment, hard delete) | +| ProductVariant | ✅ | ✅ | ✅ | ✅ | Complete (nested) | +| Category | ✅ | ✅ | ✅ | ✅ | Complete | +| Brand | ✅ | ✅ | ✅ | ✅ | Complete | +| Order | ✅ | ⚠️ | ✅ | ❌ | Missing delete (by design) | +| Customer | ✅ | ✅ | ✅ | ✅ | Complete | +| Store | ✅ | ✅ | ✅ | ⚠️ | Soft delete only | +| Organization | ✅ | ✅ | ❌ | ❌ | Missing update/delete | +| StoreStaff | ✅ | ✅ | ✅ | ✅ | Complete | +| Subscription | ✅ | ✅ | ✅ | — | N/A (state machine) | +| SubscriptionPlan | ✅ | ✅ | ✅ | ⚠️ | Should soft-delete | +| PaymentConfig | ✅ | ✅ | ✅ | ❌ | Missing delete | +| Webhook | ✅ | ✅ | ✅ | ✅ | Complete | +| LandingPage | ✅ | ✅ | ✅ | ✅ | Complete | +| Review | ✅ | ✅ | ✅ | ✅ | Complete | +| Attribute | ✅ | ✅ | ✅ | ✅ | ⚠️ Tenant leak | +| DiscountCode | ✅ | ✅ | ✅ | ✅ | Complete | +| Notification | ✅ | ✅ | ✅ | ❌ | Missing delete | +| ChatSession | ✅ | ✅ | ✅ | ✅ | Complete | +| ApiToken | ✅ | ✅ | ✅ | ✅ | Complete (revoke) | +| AuditLog | ✅ | ✅ | — | — | Read-only by design | +| User (admin) | ✅ | ✅ | ✅ | — | Admin manages status | + +--- + +## 7. Missing CRUD Operations + +| Entity | Missing Operations | Priority | +|--------|-------------------|----------| +| Organization | Update, Delete | Medium | +| PaymentConfiguration | Delete | Low | +| Notification | Delete (bulk), Archive | Low | +| InventoryReservation | No manual CRUD (cron-managed) | Low | +| PlatformActivity | Delete (cleanup) | Low | +| SearchAnalytics | Delete (cleanup) | Low | diff --git a/docs/cursor/review/08-ARCHITECTURE-BLUEPRINT.md b/docs/cursor/review/08-ARCHITECTURE-BLUEPRINT.md new file mode 100644 index 00000000..6b399058 --- /dev/null +++ b/docs/cursor/review/08-ARCHITECTURE-BLUEPRINT.md @@ -0,0 +1,464 @@ +# StormCom — Architecture Blueprint & Interaction Map + +**Date:** 2026-04-01 +**Architecture Pattern:** Monolithic Next.js App Router with Service Layer +**Deployment:** Vercel (Serverless) + +--- + +## 1. High-Level Architecture + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ INTERNET │ +├─────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ +│ │ Merchant │ │ Customer │ │ Admin │ │ External Services│ │ +│ │ Dashboard │ │Storefront│ │ Panel │ │ (FB, Stripe, etc)│ │ +│ └─────┬─────┘ └─────┬────┘ └────┬─────┘ └────────┬─────────┘ │ +│ │ │ │ │ │ +├────────┴──────────────┴─────────────┴──────────────────┴─────────────┤ +│ │ +│ ┌─────────────────────┐ │ +│ │ Vercel Edge/CDN │ │ +│ │ (Static Assets, │ │ +│ │ Image Optim.) │ │ +│ └──────────┬──────────┘ │ +│ │ │ +│ ┌──────────▼──────────┐ │ +│ │ Next.js 16 App │ │ +│ │ (App Router) │ │ +│ │ │ │ +│ │ ┌───────────────┐ │ │ +│ │ │ Middleware │ │ Rate limiting, │ +│ │ │ (rate-limit) │ │ request processing │ +│ │ └───────┬───────┘ │ │ +│ │ │ │ │ +│ │ ┌───────▼───────┐ │ │ +│ │ │ API Routes │ │ 291 route handlers │ +│ │ │ (Route │ │ │ +│ │ │ Handlers) │ │ │ +│ │ └───────┬───────┘ │ │ +│ │ │ │ │ +│ │ ┌───────▼───────┐ │ │ +│ │ │ API Middleware │ │ Auth, CSRF, tenancy, │ +│ │ │ (apiHandler) │ │ validation, permissions │ +│ │ └───────┬───────┘ │ │ +│ │ │ │ │ +│ │ ┌───────▼───────┐ │ │ +│ │ │ Service Layer │ │ 21 business services │ +│ │ │ (src/lib/ │ │ │ +│ │ │ services/) │ │ │ +│ │ └───────┬───────┘ │ │ +│ │ │ │ │ +│ └──────────┼──────────┘ │ +│ │ │ +│ ┌────────────────┼────────────────┐ │ +│ │ │ │ │ +│ ┌─────────▼─────┐ ┌──────▼──────┐ ┌─────▼──────┐ │ +│ │ PostgreSQL │ │ Redis │ │ Vercel │ │ +│ │ (Prisma ORM) │ │ (ioredis + │ │ Blob │ │ +│ │ │ │ Upstash) │ │ Storage │ │ +│ └───────────────┘ └─────────────┘ └────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 2. Application Layer Architecture + +### 2.1 Request Flow (API) + +``` +Client Request + │ + ▼ +┌────────────────┐ +│ Next.js Router │ Match route to handler +└────────┬───────┘ + │ + ┌────▼────┐ + │ Rate │ src/middleware/rate-limit.ts + │ Limiter │ (Upstash or in-memory) + └────┬────┘ + │ + ┌────▼──────────┐ + │ API Handler │ src/lib/api-middleware.ts + │ Pipeline: │ + │ 1. Auth │ NextAuth session/JWT + │ 2. CSRF │ Double-submit cookie + │ 3. Content- │ JSON validation + │ Type │ + │ 4. Tenant │ Multi-tenancy resolve + │ Context │ + │ 5. Permission │ RBAC check + │ 6. Validation │ Zod schema + │ 7. Pagination │ Query params + └────┬──────────┘ + │ + ┌────▼────────┐ + │ Route │ src/app/api/**/route.ts + │ Handler │ Business logic + └────┬────────┘ + │ + ┌────▼────────┐ + │ Service │ src/lib/services/*.service.ts + │ Layer │ Domain logic, validation + └────┬────────┘ + │ + ┌────▼────────┐ + │ Prisma │ Database queries + │ Client │ Transaction management + └────┬────────┘ + │ + ┌────▼────────┐ + │ Side │ Webhooks, emails, + │ Effects │ cache invalidation, + │ │ audit logging + └─────────────┘ +``` + +### 2.2 Request Flow (Pages) + +``` +Browser Request + │ + ▼ +┌────────────────┐ +│ Next.js Router │ Static or Dynamic route +└────────┬───────┘ + │ + ┌────▼──────────┐ ┌──────────────┐ + │ Server │───────▶│ getCached │ Session check + │ Component │ │ Session() │ + │ (RSC) │ └──────────────┘ + │ │ + │ Data Fetching │───────▶ Prisma queries + │ (async) │ (server-side) + └────┬──────────┘ + │ + ┌────▼──────────┐ + │ Client │ Hydrated on browser + │ Components │ Interactive UI + │ ("use client")│ + └────┬──────────┘ + │ + ┌────▼──────────┐ + │ State Mgmt │ Zustand stores + │ + API calls │ fetch() to API routes + └───────────────┘ +``` + +--- + +## 3. Data Architecture + +### 3.1 Multi-Tenancy Model + +``` + Platform Level + ┌─────────────┐ + │ User │ + │ (global ID) │ + └──────┬──────┘ + │ + ┌────────────┼────────────┐ + │ │ │ + ┌─────────▼──────┐ │ ┌───────▼──────┐ + │ Membership │ │ │ StoreStaff │ + │ (org-level │ │ │ (store-level │ + │ access) │ │ │ access) │ + └─────────┬──────┘ │ └───────┬──────┘ + │ │ │ + ┌─────────▼──────┐ │ ┌───────▼──────┐ + │ Organization │ │ │ Store │ + │ (tenant unit) │ │ │ (commerce │ + └─────────┬──────┘ │ │ unit) │ + │ │ └──────────────┘ + │ │ + └───────────┘ + │ + Tenant Isolation: storeId on all commerce entities + + Store ──┬── Products, Categories, Brands + ├── Orders, Customers + ├── Inventory, Fulfillment + ├── Webhooks, API Tokens + ├── Integrations (Facebook, Pathao) + ├── Landing Pages + └── Subscriptions +``` + +### 3.2 Payment Architecture + +``` +┌─────────────┐ +│ Checkout │ +│ Service │ +└──────┬──────┘ + │ +┌──────▼──────────────┐ +│ Payment │ +│ Orchestrator │ +│ (payment- │ +│ orchestrator.ts) │ +└──────┬──────────────┘ + │ + ├──────────────┬──────────────┬──────────────┐ + │ │ │ │ +┌──────▼──────┐ ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐ +│ Stripe │ │SSLCommerz │ │ bKash │ │ Nagad │ +│ Service │ │ Service │ │ Service │ │ Service │ +│ (ACTIVE) │ │ (ACTIVE) │ │ (STUB) │ │ (STUB) │ +└──────┬──────┘ └─────┬─────┘ └───────────┘ └───────────┘ + │ │ + │ │ +┌──────▼──────┐ ┌─────▼──────────┐ +│ Stripe API │ │ SSLCommerz API │ +│ (webhook) │ │ (IPN callback) │ +└─────────────┘ └────────────────┘ +``` + +### 3.3 Caching Architecture + +``` +┌─────────────────────────────────────────┐ +│ Application Code │ +├─────────────┬───────────┬───────────────┤ +│ │ │ │ +│ ┌──────────▼──┐ ┌─────▼──────┐ ┌────▼──────────┐ +│ │ cache.ts │ │ cache- │ │ edge-cache.ts │ +│ │ (main │ │ service.ts │ │ (Vercel KV) │ +│ │ cache) │ │ (advanced) │ │ │ +│ └──────┬──────┘ └─────┬──────┘ └───────────────┘ +│ │ │ +│ ┌──────▼──────┐ ┌─────▼──────┐ +│ │ ioredis │ │ ioredis │ +│ │ (TCP) │ │ (TCP) │ +│ └──────┬──────┘ └─────┬──────┘ +│ │ │ +│ ┌──────▼───────────────▼──────┐ +│ │ Redis Server │ +│ │ (or Upstash for edge) │ +│ └─────────────────────────────┘ +│ │ +└─────────────────────────────────────────┘ +``` + +--- + +## 4. Component Architecture + +### 4.1 Page Component Hierarchy + +``` +layout.tsx (Root) +├── Providers (Session, Theme, Toast, Zustand) +├── Analytics (Vercel Analytics, Speed Insights) +│ +├── (auth)/ — Auth Layout +│ ├── login/page.tsx +│ ├── signup/page.tsx +│ └── ... +│ +├── dashboard/ — Dashboard Layout +│ ├── AppSidebar (filtered by permissions) +│ ├── SiteHeader +│ └── Page Content +│ ├── products/ → ProductsPageClient +│ ├── orders/ → OrdersPageClient +│ ├── customers/ → CustomersPageClient +│ └── ... +│ +├── admin/ — Admin Layout (super admin only) +│ ├── AdminSidebar +│ ├── AdminHeader +│ └── Admin Pages +│ +├── store/[slug]/ — Storefront Layout (public) +│ ├── StoreHeader +│ ├── StoreFooter +│ └── Store Pages (products, cart, checkout) +│ +├── settings/ — Settings pages +├── chat/ — AI Chat interface +└── stormpilot/ — StormPilot assistant +``` + +### 4.2 UI Component Library + +``` +src/components/ui/ (50 Shadcn/Radix primitives) +├── Core: button, input, textarea, label, checkbox, radio-group +├── Layout: card, separator, tabs, accordion, collapsible, resizable +├── Overlay: dialog, sheet, drawer, alert-dialog, popover, tooltip +├── Navigation: dropdown-menu, command, navigation-menu, breadcrumb +├── Data: table, enhanced-data-table, badge, avatar, skeleton +├── Feedback: toast, sonner, progress, alert +├── Form: form, select, switch, slider, toggle, calendar +└── Custom: bulk-action-bar, form-dialog, loading-skeletons +``` + +--- + +## 5. Integration Architecture + +### 5.1 External Service Map + +``` +┌─────────────────────────────────────────────────┐ +│ StormCom App │ +├─────────────────────────────────────────────────┤ +│ │ +│ Auth ─────────► NextAuth.js ──► Credentials │ +│ + Magic Link │ +│ │ +│ Email ────────► Resend API │ +│ │ +│ Storage ──────► Vercel Blob │ +│ │ +│ Payments ─────► Stripe API │ +│ ──► SSLCommerz API │ +│ ──► bKash API (stub) │ +│ ──► Nagad API (stub) │ +│ │ +│ Shipping ─────► Pathao API │ +│ │ +│ Social ───────► Facebook Graph API │ +│ ──► Facebook Conversions API │ +│ ──► Facebook Messenger │ +│ │ +│ AI ───────────► Ollama (local/cloud) │ +│ │ +│ Search ───────► Elasticsearch (optional) │ +│ ──► PostgreSQL (default) │ +│ │ +│ Cache ────────► Redis (ioredis / Upstash) │ +│ │ +│ Analytics ────► Vercel Analytics │ +│ ──► Vercel Speed Insights │ +│ │ +│ Monitoring ───► Structured Logging │ +│ ──► Performance Metrics (DB) │ +│ │ +└─────────────────────────────────────────────────┘ +``` + +### 5.2 Webhook Flow + +``` +External Event (Stripe, Facebook, Pathao) + │ + ▼ +┌──────────────┐ +│ Webhook │ /api/webhooks/{provider} +│ Endpoint │ +└──────┬───────┘ + │ +┌──────▼───────┐ +│ Signature │ HMAC verification +│ Verification │ (provider-specific) +└──────┬───────┘ + │ +┌──────▼───────┐ +│ Event │ Parse & validate +│ Processing │ event payload +└──────┬───────┘ + │ +┌──────▼───────┐ +│ Business │ Update order status, +│ Logic │ sync inventory, etc. +└──────┬───────┘ + │ +┌──────▼───────┐ ┌──────────────┐ +│ Outbound │───────▶│ Merchant │ +│ Webhooks │ │ Webhook URLs │ +│ (webhook- │ └──────────────┘ +│ delivery.ts)│ +└──────────────┘ +``` + +--- + +## 6. Deployment Architecture + +``` +┌─────────────────────────────────────────────────┐ +│ Vercel Platform │ +├─────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ ┌──────────────┐ │ +│ │ Edge Network │ │ CDN │ │ +│ │ (Middleware) │ │ (Static │ │ +│ │ │ │ Assets) │ │ +│ └──────┬───────┘ └──────────────┘ │ +│ │ │ +│ ┌──────▼───────────────────────────┐ │ +│ │ Serverless Functions │ │ +│ │ (API Routes + SSR Pages) │ │ +│ │ - Cold start per request │ │ +│ │ - No persistent connections │ │ +│ │ - 10s default timeout │ │ +│ └──────┬───────────────────────────┘ │ +│ │ │ +│ ┌──────▼──────┐ ┌──────────────┐ │ +│ │ Vercel Blob │ │ Vercel KV │ │ +│ │ (Files) │ │ (Edge Cache) │ │ +│ └─────────────┘ └──────────────┘ │ +│ │ +├─────────────────────────────────────────────────┤ +│ External Services │ +│ │ +│ ┌──────────────┐ ┌──────────────┐ │ +│ │ PostgreSQL │ │ Redis │ │ +│ │ (Prisma │ │ (Upstash │ │ +│ │ Accelerate │ │ or self- │ │ +│ │ or Neon) │ │ hosted) │ │ +│ └──────────────┘ └──────────────┘ │ +│ │ +└─────────────────────────────────────────────────┘ + +Build Pipeline: + npm run vercel-build + → prisma generate + → prisma migrate deploy + → next build (with React Compiler) +``` + +--- + +## 7. Architectural Issues Identified + +### 7.1 Serverless Compatibility Issues + +| Issue | Impact | Recommendation | +|-------|--------|----------------| +| WebSocket server (socket.io) not wired to Next.js server | Real-time features non-functional on Vercel | Use SSE (already partially implemented) or Vercel's WebSocket support | +| `setTimeout` for webhook retries | Retries lost on function termination | Use a queue (Vercel Cron, BullMQ, or Inngest) | +| In-memory rate limit fallback | Fresh store per cold start | Rely on Redis only, fail-closed | +| Redis connection pooling | Each function opens connections | Use connection pooling via proxy | + +### 7.2 Scalability Bottlenecks + +| Bottleneck | Current | Recommended | +|------------|---------|-------------| +| DB rate limiting | 2-3 writes per API request | Redis-only rate limiting | +| No read replicas | All queries hit primary | Add Prisma read replicas | +| Cache stampede | All concurrent requests hit DB on cache miss | Implement SWR or lock pattern | +| Unbounded queries | Some endpoints lack pagination limits | Enforce max `take` values | +| Redis `KEYS` command | Blocks entire keyspace on invalidation | Use `SCAN` or tagged invalidation | + +### 7.3 Missing Architectural Patterns + +| Pattern | Status | Priority | +|---------|--------|----------| +| Request-scoped context | ❌ Missing | High — reduces duplicate DB queries | +| Circuit breaker | ❌ Missing | Medium — for external service calls | +| Event-driven processing | ❌ Missing | Medium — for async operations | +| Database connection pooling | ❌ Missing | High — critical for serverless | +| Feature flags | ❌ Missing | Low — for gradual rollouts | +| Blue-green deployment | ✅ Vercel handles | Built-in | +| CDN caching | ✅ Vercel CDN | Built-in | +| Auto-scaling | ✅ Vercel serverless | Built-in | diff --git a/docs/cursor/review/09-BEST-PRACTICES-SUGGESTIONS.md b/docs/cursor/review/09-BEST-PRACTICES-SUGGESTIONS.md new file mode 100644 index 00000000..a4918b64 --- /dev/null +++ b/docs/cursor/review/09-BEST-PRACTICES-SUGGESTIONS.md @@ -0,0 +1,489 @@ +# StormCom — Best Practices & Implementation Guidelines + +**Date:** 2026-04-01 +**Based on:** Latest 2026 documentation and best practices for the project's tech stack + +--- + +## 1. Next.js 16 Best Practices + +### 1.1 Server Components (Current Gap: Medium) + +**Issue:** Many dashboard pages use large client components with data fetching. +**Best Practice:** Prioritize Server Components by default, use `'use client'` only at interaction leaves. + +```typescript +// RECOMMENDED: Server Component for data-heavy pages +// src/app/dashboard/products/page.tsx +export default async function ProductsPage() { + const products = await getProducts(); // Server-side fetch + return ; +} +``` + +**Key Guidelines:** +- Render marketing pages via ISR (Incremental Static Regeneration) +- Use `generateMetadata()` instead of static `export const metadata` for dynamic pages +- Enable React Compiler (`reactCompiler: true` — already done) +- Use `unstable_cache` with tags for surgical cache invalidation + +### 1.2 Caching Strategy (Current Gap: High) + +**Current:** Mixed caching with Redis `KEYS` command and no stampede protection. + +**Recommended per-route cache shaping:** + +| Route Type | Strategy | TTL | +|------------|----------|-----| +| Product Detail (PDP) | ISR | 300-900s | +| Product Listing | ISR with revalidation | 60s | +| Cart APIs | Edge cache | 30s | +| Search Results | Dynamic + Redis | Per-query | +| Dashboard Data | No cache (real-time) | — | +| Static Content | Static generation | Infinite | + +### 1.3 Performance Targets + +Based on 2026 industry standards: + +| Metric | Target | Current | +|--------|--------|---------| +| TTFB | < 200ms | Unknown (no APM) | +| LCP (mobile) | < 2.2s P95 | Unknown | +| Checkout latency | < 2s P95 | Unknown | +| Critical JS bundle | < 200KB | Unknown | +| Build time | < 60s | ~33s (good) | + +### 1.4 Configuration Fixes + +```typescript +// next.config.ts - REMOVE these: +typescript: { + ignoreBuildErrors: true, // ← REMOVE: hides real type errors +} + +// CSP - IMPROVE: +// Replace 'unsafe-eval' 'unsafe-inline' with nonce-based approach +// Use next/script with strategy="afterInteractive" + nonces +``` + +--- + +## 2. Prisma & PostgreSQL Best Practices + +### 2.1 Row-Level Security (Priority: High) + +**Current:** Application-level `storeId` filtering only. +**Recommended:** Add PostgreSQL RLS as database-level safety net. + +```sql +-- Migration: Enable RLS on tenant tables +ALTER TABLE "Product" ENABLE ROW LEVEL SECURITY; + +CREATE POLICY tenant_isolation_product ON "Product" + USING ("storeId" = current_setting('app.current_store_id')::text); +``` + +```typescript +// Set tenant context per request +async function setTenantContext(storeId: string) { + await prisma.$executeRaw`SELECT set_config('app.current_store_id', ${storeId}, true)`; +} +``` + +### 2.2 Connection Pooling (Priority: High) + +**For Vercel Serverless:** +``` +DATABASE_URL="postgresql://user:pass@host:5432/db?connection_limit=5&pool_timeout=10" +``` + +Or use Prisma Accelerate / PgBouncer for external pooling. + +### 2.3 Query Optimization + +```typescript +// Use Prisma $transaction for atomic multi-step operations +const result = await prisma.$transaction(async (tx) => { + const order = await tx.order.create({ ... }); + await tx.product.update({ + where: { id: productId }, + data: { inventoryQty: { decrement: quantity } }, + }); + return order; +}); + +// Use select/include wisely — avoid fetching unused fields +const products = await prisma.product.findMany({ + select: { id: true, name: true, price: true, thumbnailUrl: true }, + where: { storeId, deletedAt: null }, + take: 50, +}); +``` + +### 2.4 Schema Improvements + +```prisma +// Change String fields to Json for structured data +model Store { + storefrontConfig Json? // was String? + storefrontConfigDraft Json? +} + +model Webhook { + events String[] // was String (comma-separated) +} + +model CustomRole { + permissions String[] // was String (JSON string) +} +``` + +--- + +## 3. Security Best Practices + +### 3.1 Encryption (Priority: Critical) + +```typescript +// REPLACE AES-256-CBC with AES-256-GCM +import { createCipheriv, createDecipheriv, randomBytes } from 'crypto'; + +const ALGORITHM = 'aes-256-gcm'; + +export function encrypt(text: string): string { + const iv = randomBytes(16); + const cipher = createCipheriv(ALGORITHM, key, iv); + let encrypted = cipher.update(text, 'utf8', 'hex'); + encrypted += cipher.final('hex'); + const tag = cipher.getAuthTag().toString('hex'); + return `${iv.toString('hex')}:${encrypted}:${tag}`; +} + +export function decrypt(encryptedText: string): string { + const [ivHex, encrypted, tagHex] = encryptedText.split(':'); + const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(ivHex, 'hex')); + decipher.setAuthTag(Buffer.from(tagHex, 'hex')); + let decrypted = decipher.update(encrypted, 'hex', 'utf8'); + decrypted += decipher.final('utf8'); + return decrypted; +} +``` + +### 3.2 Constant-Time Comparison (Priority: High) + +```typescript +import { timingSafeEqual } from 'crypto'; + +export function constantTimeCompare(a: string, b: string): boolean { + const bufA = Buffer.from(a); + const bufB = Buffer.from(b); + if (bufA.length !== bufB.length) { + // Compare against padding to maintain constant time + return timingSafeEqual(bufA, Buffer.alloc(bufA.length)); + } + return timingSafeEqual(bufA, bufB); +} +``` + +### 3.3 SSRF Prevention (Priority: Critical) + +```typescript +import { URL } from 'url'; +import { isIP } from 'net'; + +function isInternalUrl(urlString: string): boolean { + const url = new URL(urlString); + const hostname = url.hostname; + + if (isIP(hostname)) { + const parts = hostname.split('.').map(Number); + // Block private ranges + if (parts[0] === 10) return true; + if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return true; + if (parts[0] === 192 && parts[1] === 168) return true; + if (parts[0] === 127) return true; + if (hostname === '0.0.0.0') return true; + } + + if (hostname === 'localhost' || hostname.endsWith('.local')) return true; + if (hostname.startsWith('169.254.')) return true; // Link-local + + return false; +} + +export function validateWebhookUrl(url: string): boolean { + try { + const parsed = new URL(url); + if (!['http:', 'https:'].includes(parsed.protocol)) return false; + if (isInternalUrl(url)) return false; + return true; + } catch { + return false; + } +} +``` + +### 3.4 Rate Limiting Consolidation (Priority: High) + +Replace three implementations with a single Redis-based solution: + +```typescript +// Unified rate limiter using Upstash Redis (works in both edge and serverless) +import { Ratelimit } from '@upstash/ratelimit'; +import { redis } from './redis-upstash'; + +export const rateLimiter = { + api: new Ratelimit({ + redis, + limiter: Ratelimit.slidingWindow(100, '1 m'), + }), + auth: new Ratelimit({ + redis, + limiter: Ratelimit.slidingWindow(5, '1 m'), + }), + webhook: new Ratelimit({ + redis, + limiter: Ratelimit.slidingWindow(1000, '1 m'), + }), +}; +``` + +### 3.5 CSP Hardening + +```typescript +// Use nonce-based CSP instead of unsafe-inline/unsafe-eval +import { headers } from 'next/headers'; + +// In middleware or headers config: +const nonce = Buffer.from(crypto.randomUUID()).toString('base64'); +const csp = ` + default-src 'self'; + script-src 'self' 'nonce-${nonce}' https://vercel.live; + style-src 'self' 'nonce-${nonce}'; + img-src 'self' blob: data: https:; + connect-src 'self' https://vercel.live https://vitals.vercel-analytics.com; +`.replace(/\n/g, ' '); +``` + +--- + +## 4. Vercel Deployment Best Practices + +### 4.1 Environment Variables + +| Variable | Prefix | Notes | +|----------|--------|-------| +| `DATABASE_URL` | (none) | Server-only — never use `NEXT_PUBLIC_` | +| `NEXTAUTH_SECRET` | (none) | Server-only | +| `STRIPE_SECRET_KEY` | (none) | Server-only | +| `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY` | `NEXT_PUBLIC_` | OK for client | +| `NEXT_PUBLIC_APP_URL` | `NEXT_PUBLIC_` | OK for client | +| All other secrets | (none) | Server-only | + +### 4.2 Build Configuration + +```json +{ + "buildCommand": "npm run vercel-build", + "outputDirectory": ".next", + "installCommand": "npm install", + "framework": "nextjs" +} +``` + +### 4.3 Recommended Vercel Settings + +- Enable Vercel Firewall (WAF) for production +- Set up preview deployment protection +- Configure Edge Middleware for geolocation +- Enable Vercel Cron for scheduled jobs (subscription processing, cleanup) +- Use Vercel KV instead of self-hosted Redis for edge compatibility + +--- + +## 5. TypeScript Best Practices + +### 5.1 Remove `ignoreBuildErrors` + +```typescript +// next.config.ts — REMOVE: +typescript: { + ignoreBuildErrors: true, +} +``` + +Fix type errors instead of suppressing them. Run `tsc --noEmit` in CI. + +### 5.2 Strict Type Safety + +```typescript +// Replace 'as' casts with type guards +// BAD: +const sortOrder = searchParams.get('sortOrder') as 'asc' | 'desc'; + +// GOOD: +function isSortOrder(value: string | null): value is 'asc' | 'desc' { + return value === 'asc' || value === 'desc'; +} +const sortOrder = isSortOrder(raw) ? raw : 'desc'; +``` + +### 5.3 Use Zod Consistently + +Ensure all API routes validate input with Zod schemas: + +```typescript +const productSchema = z.object({ + name: z.string().min(1).max(255), + price: z.number().int().positive(), + storeId: z.string().cuid2(), // not cuid() + // Explicitly list allowed fields — prevent mass assignment +}); +``` + +--- + +## 6. Testing Best Practices + +### 6.1 Current Coverage: ~15% + +**Target:** 80% for services, 60% for API routes, 40% for components. + +### 6.2 Priority Test Areas + +1. **Payment processing** — Zero tests, highest financial risk +2. **Order lifecycle** — State transitions, cancellation, refund +3. **Subscription state machine** — Trial, upgrade, downgrade, cancellation +4. **Multi-tenancy isolation** — Cross-tenant data access prevention +5. **Permission enforcement** — RBAC checks on all routes + +### 6.3 E2E Test Scenarios + +```typescript +// Critical user flows for Playwright tests: +test('merchant can create product and receive order', async ({ page }) => { + // 1. Login as merchant + // 2. Create product + // 3. Open storefront + // 4. Add to cart + // 5. Checkout + // 6. Verify order in dashboard +}); + +test('admin can approve store request', async ({ page }) => { + // 1. Login as admin + // 2. View pending requests + // 3. Approve request + // 4. Verify store created +}); +``` + +--- + +## 7. Performance Optimization + +### 7.1 Bundle Size Reduction + +```typescript +// Dynamic import for heavy components +const MonacoEditor = dynamic(() => import('@monaco-editor/react'), { + ssr: false, + loading: () => , +}); + +const SwaggerUI = dynamic(() => import('@/components/api-docs-viewer'), { + ssr: false, +}); +``` + +### 7.2 Database Query Optimization + +```typescript +// Use Prisma's select to fetch only needed fields +// BAD: +const products = await prisma.product.findMany({ where: { storeId } }); + +// GOOD: +const products = await prisma.product.findMany({ + where: { storeId, deletedAt: null }, + select: { + id: true, name: true, slug: true, price: true, + compareAtPrice: true, thumbnailUrl: true, status: true, + inventoryStatus: true, inventoryQty: true, + }, + take: Math.min(limit, 100), // Enforce max + skip: offset, + orderBy: { createdAt: 'desc' }, +}); +``` + +### 7.3 Image Optimization + +Already configured well in `next.config.ts`: +- AVIF + WebP formats +- Proper `deviceSizes` and `imageSizes` +- 1-year cache TTL for versioned images +- Remote patterns for CDN sources + +--- + +## 8. Code Quality Improvements + +### 8.1 Consolidate Duplicates + +| Current Duplicate | Action | +|-------------------|--------| +| 3 rate-limit implementations | Consolidate to Upstash-based | +| 4 session-fetching approaches | Use single `getCachedSession()` | +| 2 `sanitizeHtml` functions | Keep security module version | +| 2 `product-quick-view` components | Delete duplicate at root | +| `.bak` file in components | Delete | +| `seed.ts` + `seed.mjs` + `seed-new.mjs` | Keep one, remove others | + +### 8.2 Delete Dead Code + +| File | Reason | +|------|--------| +| `src/components/landing-pages/landing-page-editor-client.tsx.bak` | Backup file | +| `src/components/product-quick-view.tsx` | Duplicate | +| `src/components/price-range-filter.tsx` | Duplicate | +| `prisma/seed.ts` | Replaced by seed.mjs | +| `prisma/seed-new.mjs` | Similar to seed.mjs | + +### 8.3 Consistent Error Handling + +```typescript +// Standard error response factory (use everywhere) +export function apiError(message: string, status: number, code?: string) { + const isProduction = process.env.NODE_ENV === 'production'; + return NextResponse.json({ + success: false, + error: isProduction && status >= 500 ? 'Internal Server Error' : message, + ...(code && { code }), + }, { status }); +} +``` + +--- + +## 9. Monitoring & Observability + +### 9.1 Recommended Stack + +| Tool | Purpose | +|------|---------| +| Vercel Analytics | Web vitals, page views | +| Vercel Speed Insights | Performance monitoring | +| Sentry | Error tracking, performance | +| Vercel Cron | Scheduled jobs | +| Structured Logging | Already partially implemented | + +### 9.2 Key Metrics to Track + +- API response times (P50, P95, P99) +- Database query counts per request +- Cache hit/miss ratios +- Payment success/failure rates +- Subscription churn rate +- Error rate by route diff --git a/docs/cursor/review/10-PROGRESS-STATUS.md b/docs/cursor/review/10-PROGRESS-STATUS.md new file mode 100644 index 00000000..9705f499 --- /dev/null +++ b/docs/cursor/review/10-PROGRESS-STATUS.md @@ -0,0 +1,115 @@ +# StormCom — Review Progress Status + +**Last Updated:** 2026-04-01 +**Review Agent:** Cloud Agent (Comprehensive Repository Review) + +--- + +## Task Completion Status + +| # | Task | Status | Notes | +|---|------|--------|-------| +| 1 | Explore repository structure | ✅ Complete | 936 files in src/, full tree mapped | +| 2 | Review all src/ files (code review) | ✅ Complete | All lib/, services/, components/, hooks/ reviewed | +| 3 | Review Prisma database schema | ✅ Complete | 42 models, 24 enums, 38 migrations analyzed | +| 4 | Audit package.json dependencies | ✅ Complete | 84 packages audited, 5 unused identified | +| 5 | List all routes (npm run build) | ✅ Complete | Build successful, 402 routes verified | +| 6 | Cross-validate docs with code | ✅ Complete | All 3 existing docs validated against codebase | +| 7 | Set up development environment | ✅ Complete | npm install, prisma generate, next build successful | +| 8 | Create comprehensive findings doc | ✅ Complete | 01-COMPREHENSIVE-CODE-REVIEW.md | +| 9 | Create Traceability Matrix | ✅ Complete | 06-TRACEABILITY-MATRIX.md | +| 10 | Create CRUD Matrix | ✅ Complete | 07-CRUD-MATRIX.md | +| 11 | Create Architecture Blueprint | ✅ Complete | 08-ARCHITECTURE-BLUEPRINT.md | +| 12 | Document security vulnerabilities | ✅ Complete | 05-SECURITY-VULNERABILITIES.md (66 findings) | +| 13 | Research best practices & suggestions | ✅ Complete | 09-BEST-PRACTICES-SUGGESTIONS.md | +| 14 | Create progress tracking file | ✅ Complete | This file | + +--- + +## Tasks Not Performed (Require Live Environment) + +| Task | Reason | Prerequisite | +|------|--------|-------------| +| Run application with real data | No database connection available | DATABASE_URL with live PostgreSQL | +| Login with merchant credentials | No auth credentials available | Seeded database + known credentials | +| Navigate all UI pages manually | No browser automation configured | Running dev server + database | +| Perform real-life actions on UI | No live environment | Full stack running | +| Test payment flows end-to-end | No payment gateway credentials | Stripe/SSLCommerz test keys | + +**Note:** These tasks require a fully provisioned environment with: +1. PostgreSQL database with seeded data +2. Redis instance for caching/rate limiting +3. Environment variables configured (`.env` with real values) +4. External service credentials (Stripe, Resend, etc.) + +--- + +## Documentation Deliverables + +All documents are saved in `/docs/cursor/review/`: + +| File | Size | Content | +|------|------|---------| +| `00-PROJECT-OVERVIEW.md` | ~3KB | Project summary, tech stack, document index | +| `01-COMPREHENSIVE-CODE-REVIEW.md` | ~15KB | Line-by-line code review, 55+ findings | +| `02-DATABASE-SCHEMA-REVIEW.md` | ~8KB | Schema analysis, design issues, enum review | +| `03-DEPENDENCY-AUDIT.md` | ~10KB | Package validation, unused deps, bundle concerns | +| `04-ROUTE-CROSS-VALIDATION.md` | ~12KB | All routes verified against build + docs | +| `05-SECURITY-VULNERABILITIES.md` | ~12KB | 66 security findings (10C, 16H, 28M, 12L) | +| `06-TRACEABILITY-MATRIX.md` | ~15KB | Requirements → code mapping, test coverage | +| `07-CRUD-MATRIX.md` | ~10KB | CRUD operations for all 22 entities | +| `08-ARCHITECTURE-BLUEPRINT.md` | ~12KB | System architecture, data flow, deployment | +| `09-BEST-PRACTICES-SUGGESTIONS.md` | ~12KB | Latest research-based improvements | +| `10-PROGRESS-STATUS.md` | ~3KB | This status file | + +--- + +## Key Metrics Summary + +| Metric | Value | +|--------|-------| +| **Total Files Reviewed** | 936 | +| **Security Findings** | 66 (10 Critical, 16 High, 28 Medium, 12 Low) | +| **Unused Dependencies** | 5 (radix-ui, react-is, baseline-browser-mapping, tw-animate-css, @testing-library/user-event) | +| **Dead Code Files** | 3 (.bak file, 2 duplicate components) | +| **Duplicate Implementations** | 6 (rate limiting ×3, session ×4, sanitize ×2, etc.) | +| **Missing Test Coverage** | ~85% of functional requirements untested | +| **Seed Script Issues** | 2 (field name mismatch, duplicate scripts) | +| **Schema Design Issues** | 8 (JSON as String, missing indexes, enum duplicates) | +| **Architecture Gaps** | 4 (no RLS, no request context, no circuit breaker, no event queue) | +| **Build Time** | ~33 seconds (good) | +| **Build Warnings** | 0 (type errors suppressed by ignoreBuildErrors) | + +--- + +## Recommended Next Steps (Priority Order) + +### Immediate (Block Deployment) +1. Fix authentication on `/api/admin/setup-payment-configs` (C-03) +2. Add auth to `/api/store/[slug]/orders/[orderId]/verify-payment` (C-02) +3. Restrict order PII exposure on public endpoints (C-04) +4. Add SSRF prevention to webhook delivery (C-01) + +### Short Term (Next 1-2 Sprints) +5. Switch encryption to AES-256-GCM (C-07) +6. Replace DB-based rate limiting with Redis (C-05) +7. Fix mass assignment in product routes (H-01) +8. Fix constant-time comparison (H-07) +9. Sanitize error responses in production (H-13) +10. Add tenant isolation to attribute service (C-09) + +### Medium Term +11. Implement PostgreSQL RLS +12. Consolidate rate limiting to single implementation +13. Unify session management +14. Add comprehensive test coverage (target 60%+) +15. Harden CSP policy +16. Complete bKash/Nagad payment providers or remove + +### Long Term +17. Add request-scoped context +18. Implement circuit breaker for external services +19. Add event-driven processing (queue) +20. Set up APM/observability (Sentry) +21. Implement feature flags +22. Add database read replicas diff --git a/package-lock.json b/package-lock.json index ed9d32c5..fd95b8c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -241,6 +241,17 @@ } } }, + "node_modules/@auth/prisma-adapter/node_modules/nodemailer": { + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.13.tgz", + "integrity": "sha512-PNDFSJdP+KFgdsG3ZzMXCgquO7I6McjY2vlqILjtJd0hy8wEvtugS9xKRF2NWlPNGxvLCXlTNIae4serI7dinw==", + "license": "MIT-0", + "optional": true, + "peer": true, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", @@ -451,7 +462,7 @@ "version": "7.29.2", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.29.0" @@ -1787,9 +1798,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1806,9 +1814,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1825,9 +1830,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1844,9 +1846,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1863,9 +1862,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1882,9 +1878,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1901,9 +1894,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1920,9 +1910,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1939,9 +1926,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1964,9 +1948,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1989,9 +1970,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -2014,9 +1992,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -2039,9 +2014,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -2064,9 +2036,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -2089,9 +2058,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -2114,9 +2080,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -2362,9 +2325,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2381,9 +2341,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2400,9 +2357,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2419,9 +2373,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3019,6 +2970,20 @@ "url": "https://dotenvx.com" } }, + "node_modules/@prisma/config/node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" + } + }, "node_modules/@prisma/config/node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -5626,9 +5591,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5646,9 +5608,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5666,9 +5625,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5686,9 +5642,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5706,9 +5659,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5726,9 +5676,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6102,9 +6049,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6122,9 +6066,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6142,9 +6083,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -6162,9 +6100,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -7043,9 +6978,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7060,9 +6992,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -7077,9 +7006,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7094,9 +7020,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7111,9 +7034,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -7128,9 +7048,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7145,9 +7062,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -7162,9 +7076,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -11959,9 +11870,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -11983,9 +11891,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -12007,9 +11912,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -12031,9 +11933,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -13646,6 +13545,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true,