Skip to content

Documentation & Code Review Findings

Review Date: 2026-02-12 Review Type: Adversarial General Review Scope: docs/index.md + docs/architecture/*.md (7 files) Status: Tracking

Summary

Category Round 1 Round 2 Round 3 Round 4 Round 5 Total Description
A — Doc contradictions 6 5 8 5 8 32 Docs disagree with each other or with source code
B — Code/architecture issues 4 4 0 0 0 8 Problems in the actual codebase, not just docs
C — Missing documentation 5 0 2 1 0 8 Important sections never written
D — Introduced by fixes 0 1 1 2 3 7 Regressions from prior fix rounds
Total 15 10 11 8 11 55

Progress

# Category Status Title
1 A [x] Entity schema contradictions (backend.md vs database.md)
2 A [x] Blog-Tag relationship contradicts across docs
3 A [x] Blog image field naming disagreement
4 A [x] Webhook endpoint paths contradictory
5 B [ ] Typos baked into codebase filenames/entities
6 B [ ] JWT in non-httpOnly cookie (security)
7 C [x] Node.js version requirements contradictory
8 C [x] Frontend is JS not TS — never acknowledged
9 B [ ] Cron jobs broken on Vercel (serverless)
10 B [ ] Redundant soft-delete tracking (isDeleted + deletedAt)
11 C [x] Two charting libs + two package managers, no rationale
12 A [x] ER diagram severely incomplete
13 A [x] Rate limiting figures inconsistent
14 C [x] No testing documentation
15 C [x] No migration strategy documented
16 A [x] database.md entity code blocks systematically wrong (9 entities)
17 A [x] api.md email template endpoint uses wrong field names
18 A [x] database.md BlogCategory relation contradicts itself
19 A [x] database.md falsely claims Setting.key is unique
20 D [x] frontend.md tech stack table broken by blockquote insertion
21 A [x] "17 API hook domains" but only 16 listed
22 A [x] frontend.md page counts wrong in section headers
23 C [x] Two date libraries in backend, no rationale documented
24 C [x] Swagger/API docs endpoint undocumented
25 A [x] integration.md production cookies still suggest httpOnly
26 A [x] backend.md event handler name reproduces typo without flagging
27 A [x] Role displayName missing from database.md
28 A [x] api.md POST /contacts uses wrong field names
29 A [x] api.md POST /menu-items uses wrong field names
30 C [x] 8 modules have zero endpoint documentation in api.md
31 D [x] nod_env code typo reproduced without flagging
32 A [x] Swagger default credentials documented without security warning
33 D [x] Page count heading still says 73 (regression from Finding 22)
34 A [x] database.md fabricates PackageCategory ↔ Package relation
35 A [x] database.md ProductCategory entity fabricated (slug, isActive don't exist; missing description)
36 A [x] database.md ER diagrams still wrong for InviteUser, Coupon, Payment
37 A [x] database.md Otp entity: wrong class name + silently "corrected" optHash typo
38 A [x] database.md missing fields in 4 entity code blocks (BlogCategory, UserSetting, LoginAttempt, Menu)
39 D [x] index.md Repository Structure still says "73 routes" and "17 domains"
40 D [x] frontend.md directory structure says "17 domains" contradicting own heading
41 A [x] api.md POST /invite-users body shows fabricated roleId field
42 A [x] backend.md says "12 middleware files" but source has 13 (missing requireStripe.ts)
43 D [x] backend.md sequrity.ts not annotated with [sic] in directory listing
44 A [x] database.md UserSetting twoFactorProvider enum missing sms option
45 A [x] database.md Otp entity missing createdAt and updatedAt timestamps

Detailed Findings

Finding 1 — Entity schema contradictions (backend.md vs database.md)

  • Category: A (Doc contradiction)
  • Severity: High
  • Status: Not started
  • Files: docs/architecture/backend.md, docs/architecture/database.md

Problem: The two documents describe fundamentally different schemas for the same entities: - EmailTemplate in backend.md: title, type (unique), subject, elements (JSONB), html - EmailTemplate in database.md: name, slug (unique), subject, body, variables (JSON) - BlogViewCount in backend.md: id, blogId, count - BlogView in database.md: id, blogId, ip, createdAt - Setting in backend.md: display_name, details, backupCodes, order (absent in database.md)

Resolution: Verified against source code. backend.md was correct; database.md was wrong. Fixed EmailTemplate, BlogViewCount, and Setting entity definitions in database.md to match actual source. Status: RESOLVED (2026-02-12)


Finding 2 — Blog-Tag relationship contradicts across docs

  • Category: A (Doc contradiction)
  • Severity: High
  • Status: Not started
  • Files: docs/architecture/backend.md, docs/architecture/database.md

Problem: backend.md says BlogTag has blogId field (OneToMany from Blog — each tag belongs to one blog). database.md defines BlogTags with no blogId, using @ManyToMany with @JoinTable() (shared tags across blogs). These are architecturally opposite patterns.

Resolution: Verified — tags are OneToMany from Blog (each tag belongs to one blog via blogId). backend.md was correct. Fixed database.md BlogTags → BlogTag with correct ManyToOne relationship and blogId. Status: RESOLVED (2026-02-12)


Finding 3 — Blog image field naming disagreement

  • Category: A (Doc contradiction)
  • Severity: Medium
  • Status: Not started
  • Files: docs/architecture/backend.md, docs/architecture/database.md, docs/architecture/api.md

Problem: backend.md says Blog has imageUrl and imageAlt. database.md says featuredImage. api.md uses featuredImage in POST example.

Resolution: Verified — actual field names are imageUrl and imageAlt. Fixed database.md Blog entity and api.md POST /blogs request example. Status: RESOLVED (2026-02-12)


Finding 4 — Webhook endpoint paths contradictory

  • Category: A (Doc contradiction)
  • Severity: Medium
  • Status: Not started
  • Files: docs/architecture/backend.md, docs/architecture/api.md

Problem: backend.md says webhooks are at /webhooks/*. api.md says Stripe is POST /stripe and LemonSqueezy is POST /lemonsqueezy (bare root-level paths, no /webhooks/ prefix).

Resolution: Verified — webhooks are mounted via app.use("/", webhookRouters) with /webhooks prefix, making paths /webhooks/stripe and /webhooks/lemonsqueezy. Fixed api.md paths. Also fixed Stripe event names in both api.md and backend.md (was invoice.paid, actually invoice.payment_succeeded; was missing payment_intent.payment_failed, customer.subscription.created; LemonSqueezy was missing order_created, order_updated). Status: RESOLVED (2026-02-12)


Finding 5 — Typos baked into codebase filenames/entities

  • Category: B (Code issue)
  • Severity: Medium
  • Status: Not started
  • Files: Actual source code files

Problem: Multiple typos exist in the actual source code, not just documentation: - sequrity.ts → should be security.ts (middleware file) - subscribtionExpire.ts → should be subscriptionExpire.ts (cron job) - optHash → should be otpHash (OtpVerification entity column) - Cupon entity → should be Coupon (entity name, table name, everywhere) - Sass-boilerplate-frontend-v1/ → should be SaaS-boilerplate-frontend-v1/ (directory name) - nod_env config key → should be node_env (config/index.ts line 78, used in dbConfig.ts)

Resolution: Rename files, entity names, and column names. Requires database migration for column/table renames. Frontend directory rename may require updating deployment configs. This is a breaking change — plan carefully.

Notes: The Cupon and optHash renames require database migrations. Directory rename affects git history and deployment configs.


  • Category: B (Code/architecture issue)
  • Severity: High
  • Status: Not started
  • Files: Frontend auth code, docs/architecture/integration.md

Problem: integration.md shows setCookie("token", response.token, { maxAge: ..., path: "/" }) with no httpOnly flag. Frontend JS reads this cookie via getCookie("token"). Later, integration.md suggests production cookies "should be" httpOnly: true — but this is incompatible with the current design where frontend JS reads the cookie directly.

Resolution: This requires an architectural decision: - Option A: Keep JS-accessible cookie (current) — remove the misleading "should be httpOnly" production suggestion, document the XSS risk and mitigations. - Option B: Move to httpOnly cookies set by the backend — requires reworking the auth flow so the backend sets the cookie in the response and the frontend never touches the token directly.


Finding 7 — Node.js version requirements contradictory

  • Category: C (Missing/wrong documentation)
  • Severity: Low
  • Status: Not started
  • Files: docs/index.md, docs/architecture/index.md

Problem: Backend says "Node.js 16+", frontend says "Node.js 18+". Next.js 15 + React 19 require Node 18.17+. Having different Node requirements for a project you develop locally is impractical.

Resolution: Verified — neither package.json has an engines field. Next.js 15.3.6 requires Node 18.17+. Unified all docs (index.md, architecture/index.md, backend.md) to state "Node.js 18.17+" as single requirement. Added note suggesting adding engines field to both package.json files. Status: RESOLVED (2026-02-12)


Finding 8 — Frontend is JS not TS, never acknowledged

  • Category: C (Missing documentation)
  • Severity: Low
  • Status: Not started
  • Files: docs/architecture/frontend.md

Problem: Every frontend file is .js/.jsx, not TypeScript. The docs never mention this or explain why, despite the backend being fully TypeScript and all frontend tooling having first-class TS support.

Resolution: Added "Language" section to frontend.md acknowledging the frontend is JavaScript (.js/.jsx), noting that TypeScript migration is possible but not yet implemented. Status: RESOLVED (2026-02-12)


Finding 9 — Cron jobs broken on Vercel (serverless)

  • Category: B (Code/architecture issue)
  • Severity: High
  • Status: Not started
  • Files: saas-boilerplate/src/app/cron/, docs/architecture/backend.md

Problem: initializeCronJobs() runs in the middleware pipeline — cron jobs don't start until the first HTTP request. On Vercel (serverless), functions spin down between invocations, so cron jobs (subscriptionExpire, scheduleResetLoginAttempts) cannot persist.

Resolution: Options: - Option A: Use Vercel Cron Jobs (vercel.json cron config) to hit dedicated API endpoints that perform the cron logic. - Option B: Use an external cron service (e.g., cron-job.org) to hit endpoints. - Option C: Document that cron jobs only work in traditional server mode (not serverless) and note the limitation.


Finding 10 — Redundant soft-delete tracking

  • Category: B (Code issue)
  • Severity: Medium
  • Status: Not started
  • Files: Entity files in saas-boilerplate/src/entity/

Problem: Entities like User, Role, Permission have both isDeleted: boolean AND @DeleteDateColumn() deletedAt: Date. TypeORM soft delete already filters by deletedAt IS NULL. The boolean creates consistency risk (what if isDeleted = true but deletedAt IS NULL?).

Resolution: Verify which mechanism is actually used in service layer queries. Remove the redundant one. If isDeleted is used in manual queries, migrate those to use deletedAt and drop the boolean column. Requires migration.


Finding 11 — Two charting libs + two package managers, no rationale

  • Category: C (Missing documentation)
  • Severity: Low
  • Status: Not started
  • Files: docs/index.md, docs/architecture/frontend.md

Problem: Both ApexCharts and Recharts are listed. Backend uses yarn, frontend uses npm. No explanation for either duplication.

Resolution: Added notes to docs: frontend.md tech stack table now annotates ApexCharts (dashboard analytics) vs Recharts (supplementary) with a consolidation suggestion. index.md Environment Requirements section now documents the actual package manager situation (backend has both lock files, frontend is npm-only). Status: RESOLVED (2026-02-12)


Finding 12 — ER diagram severely incomplete

  • Category: A (Doc issue)
  • Severity: Medium
  • Status: Not started
  • Files: docs/architecture/database.md

Problem: The ER diagram shows ~10 of 29 entities. Payment, Purchase, Coupon, Product, ProductCategory, GenericPage, EmailTemplate, ContactMessage, InviteUser, Setting, AppConfig, Token, OTP, LoginAttempt, Logger are all missing.

Resolution: Replaced single incomplete diagram with 4 domain-grouped sub-diagrams covering all 29 entities: Auth & User Management, Subscriptions & Payments, Content Management, Navigation/Config/System. Status: RESOLVED (2026-02-12)


Finding 13 — Rate limiting figures inconsistent

  • Category: A (Doc contradiction)
  • Severity: Medium
  • Status: Not started
  • Files: docs/architecture/api.md

Problem: General section says "100 req/min per IP" and "Auth: 10 req/min per IP." Inline endpoint docs say login is "100 req/15min" and login-otp is "5 req/15min." Different windows and limits.

Resolution: Verified actual values: default 100/1min, login 100/15min, login-otp 5/15min, verify-login-otp 10/15min. Replaced vague summary in api.md with per-endpoint breakdown matching source code. Status: RESOLVED (2026-02-12)


Finding 14 — No testing documentation

  • Category: C (Missing documentation)
  • Severity: High
  • Status: Not started

Problem: Zero mention of tests, test frameworks, test coverage, or how to run tests across all 7 doc files. Development commands list dev, build, lint, seed but no test.

Resolution: Verified — zero test files, zero test scripts, zero testing framework dependencies in both backend and frontend. Added "Testing" section to index.md acknowledging the gap and providing recommended setup instructions (Jest + Supertest for backend, Vitest + Testing Library for frontend). Status: RESOLVED (2026-02-12)


Finding 15 — No migration strategy documented

  • Category: C (Missing documentation)
  • Severity: High
  • Status: Not started

Problem: 29 entities documented but no mention of how schema changes are applied. Is synchronize: true used? Are there migration files? How does a developer add a column?

Resolution: Verified — synchronize is conditional (config.nod_env === 'development'), migrations array is empty, no migrations directory exists. Added "Migration Strategy" section to database.md documenting the current approach (auto-sync in dev, nothing in prod), its implications, and how to add a proper migration workflow with TypeORM CLI commands. Status: RESOLVED (2026-02-12)


Finding 16 — database.md entity code blocks systematically wrong (9 entities)

  • Category: A (Doc contradiction)
  • Severity: Critical
  • Status: Not started
  • Files: docs/architecture/database.md (entity code blocks), actual source in saas-boilerplate/src/entity/

Problem: Round 1 (Finding 1) fixed only EmailTemplate, BlogViewCount, and Setting. The remaining entity code blocks in database.md are fabricated — they describe schemas that don't match the actual source code. Verified against source for each:

Entity database.md says Actual source has
Product image (singular), no discountPrice/currency images (string array), discountPrice, currency, slug
Cupon discount, type (percentage/fixed), maxUses, usedCount discountType (percent/fixed), amountOff, currency, duration (once/repeating/forever), durationInMonths, stripeCouponId
Purchase amount, stripeSessionId, status paymentId, couponId, originalPrice, discountAmount, amountPaid
Payment userId, provider, providerPaymentId No userId, method enum (stripe/paypal/lemonsqueezy), referenceId, paymentDate
GenericPage content, isActive, no image description, status enum (draft/published/archived), image
ContactMessage message, subject, isRead Only details (no subject, no isRead)
AppConfig key, value, type key (unique), displayName, value, isEncrypted (no type)
MenuItem label, url, icon title, link, iconClass, plus linkType, target, color, postType, postId, parameters
InviteUser email, roleId, token, invitedBy Only email (unique), status (no roleId, token, or invitedBy)
Logger level, message, meta, timestamp status, responseTime, success, errorMessage, userId, ip, requestedAt

Resolution: Replaced all 10 entity code blocks in database.md with schemas verified against actual source files. Also updated ER diagrams (GenericPage, Product, MenuItem, AppConfig, ContactMessage, Logger fields). Status: RESOLVED (2026-02-12)


Finding 17 — api.md email template endpoint uses wrong field names

  • Category: A (Doc contradiction)
  • Severity: High
  • Status: Not started
  • Files: docs/architecture/api.md (line ~667), saas-boilerplate/src/app/modules/v1/EmailTemplate/

Problem: The POST /email-templates example body shows:

{ "name": "Welcome Email", "slug": "welcome-email", "subject": "...", "body": "<h1>...</h1>", "variables": ["siteName", "userName"] }
But the actual validation schema and entity use completely different fields: - name → should be title - slug → should be type - body → should be html - variables → does not exist (entity has elements as JSONB blocks)

Anyone using this API doc to build a client will get 400 validation errors.

Resolution: Replaced POST /email-templates example in api.md with correct fields: { title, type, subject, html }. Added note about elements JSONB field. Status: RESOLVED (2026-02-12)


Finding 18 — database.md BlogCategory relation contradicts itself

  • Category: A (Doc contradiction)
  • Severity: Medium
  • Status: Not started
  • Files: docs/architecture/database.md (lines ~563 vs ~472)

Problem: Within the same file, the BlogCategory entity code block shows:

@OneToMany(() => Blog, (blog) => blog.category)
blogs: Blog[];
But the Blog entity code block (already fixed in Round 1) shows:
@ManyToMany(() => BlogCategory, (category) => category.blogs, { cascade: true })
@JoinTable({ name: "blog_categories_pivot" })
categories: BlogCategory[];
Actual source confirms ManyToMany on both sides via blog_categories_pivot. The BlogCategory code block was never updated during Round 1.

Resolution: Changed BlogCategory blogs relation from @OneToMany to @ManyToMany(() => Blog, (blog) => blog.categories) in database.md. Status: RESOLVED (2026-02-12)


Finding 19 — database.md falsely claims Setting.key is unique

  • Category: A (Doc contradiction)
  • Severity: Medium
  • Status: Not started
  • Files: docs/architecture/database.md (line ~1303)

Problem: The Compound Indexes section lists Setting.key (unique). But the actual Setting entity has no unique constraint on key:

@Column({ type: "varchar", length: 255 })
key: string;
Compare with AppConfig which genuinely has @Index(["key"], { unique: true }). This is misleading for anyone writing seed data or queries that depend on key uniqueness.

Resolution: Removed (unique) from Setting.key in the Compound Indexes list in database.md. Status: RESOLVED (2026-02-12)


Finding 20 — frontend.md tech stack table broken by blockquote insertion

  • Category: D (Introduced by fixes)
  • Severity: Medium
  • Status: Not started
  • Files: docs/architecture/frontend.md (lines 29-41)

Problem: The Round 1 fix for Finding 11 inserted a > **Note**: Two charting libraries... blockquote (line 29) between the Recharts table row and the Animations table row. This breaks the markdown table — everything from Animations onwards (Framer Motion, @dnd-kit, Lucide React, date-fns, Axios, cookies-next, jwt-decode, react-hot-toast, next-themes, PrismJS, transliteration, react-day-picker) renders as plain text, not as table rows. Twelve technologies become invisible in rendered output.

Resolution: Moved the blockquote below the table so all 12 technology rows render correctly. Table is now intact. Status: RESOLVED (2026-02-12)


Finding 21 — "17 API hook domains" but only 16 listed

  • Category: A (Doc contradiction)
  • Severity: Low
  • Status: Not started
  • Files: docs/architecture/frontend.md (line 304), docs/index.md (line 22)

Problem: frontend.md line 304 explicitly enumerates: auth, blogs, contacts, dashboard, email-templates, invited-users, menu, menu-builder, packages, pages, permissions, products, public, roles, settings, users — that's 16, not 17. The "17" count is repeated in index.md line 22 and the project-scan-report.json. Either a domain was miscounted or one was removed and the count never updated.

Resolution: Verified 16 directories under src/api/. Updated "17" → "16" in frontend.md (2 occurrences), index.md (text + metadata table), and architecture/index.md. Status: RESOLVED (2026-02-12)


Finding 22 — frontend.md page counts wrong in section headers

  • Category: A (Doc contradiction)
  • Severity: Low
  • Status: Not started
  • Files: docs/architecture/frontend.md (lines ~164, ~179)

Problem: Two section headers have wrong page counts: - "Dashboard — Content Management (10 pages)" but the table lists 11 routes (includes blogs/tags which was missed in the count) - "Dashboard — Administration (9 pages)" but the table lists 11 routes (settings/profile and settings/menu-builder were missed)

The overall "73 pages" total is likely also wrong given these discrepancies.

Resolution: Fixed section headers: Content Management 10→11, Administration 9→11. Updated total 73→~67 in frontend.md (2 occurrences), index.md (text + metadata table), and architecture/index.md. Status: RESOLVED (2026-02-12)


Finding 23 — Two date libraries in backend, no rationale documented

  • Category: C (Missing documentation)
  • Severity: Low
  • Status: Not started
  • Files: docs/architecture/backend.md (line 35)

Problem: backend.md tech stack lists both date-fns 3.6 and luxon 3.4 for "Date manipulation". No explanation of which is used where or why both are needed. This mirrors the dual charting library issue (Finding 11, now documented for frontend) but was never addressed for the backend.

Resolution: Investigated — date-fns is minimally used (one import in coupon service, possibly unused); luxon is installed but has zero imports. Added annotation to backend.md tech stack table noting both are underused and suggesting consolidation/removal. Status: RESOLVED (2026-02-12)


Finding 24 — Swagger/API docs endpoint undocumented

  • Category: C (Missing documentation)
  • Severity: Medium
  • Status: Not started
  • Files: docs/architecture/api.md, docs/architecture/backend.md (line 185)

Problem: backend.md lists /api/v1/docs as a Swagger module and swaggerAuthMiddleware.ts in the middleware directory. But api.md — the API reference document — never mentions this endpoint. No documentation of: how to access the Swagger UI, what URL to open, what credentials the swaggerAuthMiddleware requires, or what it looks like.

Resolution: Added "Swagger / API Explorer" section to api.md documenting the URL (/api/v1/docs), Basic Auth credentials (env vars DOCS_EMAIL/DOCS_PASSWORD), session persistence, and JSON spec endpoint. Status: RESOLVED (2026-02-12)


Finding 25 — integration.md production cookies still suggest httpOnly

  • Category: A (Doc contradiction)
  • Severity: Medium
  • Status: Not started
  • Files: docs/architecture/integration.md (lines 469-479)

Problem: The "Cookie Settings (Production)" section at line 473 recommends httpOnly: true for production cookies. But the entire auth architecture (documented in the same file, lines 68-99) depends on the frontend reading the token cookie via getCookie("token") — which is impossible with httpOnly cookies. This was identified as part of Finding 6 but the doc section was never removed or corrected. The result is the same document giving contradictory instructions: "store the token in a JS-accessible cookie" AND "make production cookies httpOnly".

Resolution: Rewrote the production cookie section in integration.md: removed misleading httpOnly: true suggestion, added prominent warning explaining why httpOnly is incompatible with the current architecture, documented XSS mitigations to compensate. Status: RESOLVED (2026-02-12)


Finding 26 — backend.md event handler name reproduces typo without flagging

  • Category: A (Doc issue)
  • Severity: Low
  • Status: Not started
  • Files: docs/architecture/backend.md (line 294)

Problem: The Event System table lists handler resetSubscribtionStatus — faithfully reproducing the source code typo (subscribtion instead of subscription). Finding 5 tracked the filename typo subscribtionExpire.ts but the event handler name is a separate identifier in a separate file. The docs reproduce the typo without noting it, making it look intentional.

Resolution: Added [sic] annotation to the handler name in backend.md event system table. Will be fully resolved when Finding 5 (code typo renames) is implemented. Status: RESOLVED (2026-02-12)


Finding 27 — Role displayName field missing from database.md

  • Category: A (Doc contradiction)
  • Severity: Medium
  • Status: Not started
  • Files: docs/architecture/database.md (Role entity)

Problem: backend.md entity summary lists Role with "id, name, displayName". database.md Role entity code block had no displayName column. Verified against source: src/entity/Role.ts line 26–27 confirms @Column({ nullable: true, default: null }) displayName: string. backend.md was correct; database.md was incomplete (missed during Findings 1 and 16).

Resolution: Added displayName column (nullable, default null) to Role entity code block in database.md. Status: RESOLVED (2026-02-12)


Finding 28 — api.md POST /contacts uses wrong field names

  • Category: A (Doc contradiction)
  • Severity: High
  • Status: Not started
  • Files: docs/architecture/api.md

Problem: api.md POST /contacts showed subject and message. Verified against source: validation schema (contact.validation.ts) expects name (2–100 chars), email (valid, max 255), details (10–5000 chars). No subject or message field exists. Same pattern as Finding 17.

Resolution: Replaced POST /contacts request body in api.md with correct fields (name, email, details) and added validation constraints. Status: RESOLVED (2026-02-12)


Finding 29 — api.md POST /menu-items uses wrong field names

  • Category: A (Doc contradiction)
  • Severity: High
  • Status: Not started
  • Files: docs/architecture/api.md

Problem: api.md POST /menu-items showed label, url, icon, permission (singular). Verified against source: validation schema (menuItem.validation.ts) expects title, link, iconClass, permissions (plural array), plus linkType, target, color, parentId, order, postType, postId, parameters. 4/4 documented field names were wrong. Also, the endpoint accepts an array of items, not a single object.

Resolution: Replaced POST /menu-items request body in api.md with correct fields (array format), listed all optional fields, noted required fields (menuId, title, link). Status: RESOLVED (2026-02-12)


Finding 30 — 8 modules have zero endpoint documentation in api.md

  • Category: C (Missing documentation)
  • Severity: High
  • Status: Not started
  • Files: docs/architecture/api.md

Problem: 8 modules listed in backend.md had zero endpoint docs in api.md. Verified all 8 against source route files:

Module Endpoints verified
Purchase GET /, GET /me
AppConfig GET /, GET /:id, POST /, PATCH /:id, DELETE /:id
UserSetting GET /, GET /me, GET /:id, PUT /2fa/email, PUT /2fa/google/setup, PATCH /2fa/google/verify, PATCH /2fa/google/disable, POST /2fa/generate-backup-codes
Slug POST /
PackageCategory GET /, POST /, PATCH /bulk-restore, PATCH /:id, DELETE /:id
BlogTag GET /, GET /:id, POST /, PATCH /bulk-delete, PATCH /bulk-restore, PATCH /:id, PATCH /:id/restore, DELETE /:id, DELETE /:id/permanent
ProductCategory GET /all, GET /, GET /:id, POST /, PATCH /:id, DELETE /:id
Routes GET / (expanded from 1-line stub)

Resolution: Added all 8 module sections to api.md with method, path, and auth requirements verified against source route files. Total: ~37 new endpoints documented. Status: RESOLVED (2026-02-12)


Finding 31 — nod_env code typo reproduced without flagging

  • Category: D (Introduced by Finding 15 fix)
  • Severity: Medium
  • Status: Not started
  • Files: docs/architecture/database.md (migration section), saas-boilerplate/src/config/index.ts, saas-boilerplate/src/config/dbConfig.ts

Problem: Verified against source — nod_env IS the actual config key (config/index.ts line 78: nod_env: process.env.NODE_ENV). The config object also has env, production, and mode keys for NODE_ENV (4 redundant mappings). dbConfig.ts line 11 uses config.nod_env. The Finding 15 fix faithfully reproduced the source code typo without flagging it, same pattern as Finding 26.

Note: nod_env should be added to Finding 5's list of code typos.

Resolution: Added [sic] annotation to nod_env in database.md migration section, same treatment as Finding 26. Will be fully resolved when Finding 5 (code typo renames) is implemented. Status: RESOLVED (2026-02-12)


Finding 32 — Swagger default credentials documented without security warning

  • Category: A (Doc gap / security)
  • Severity: Medium
  • Status: Not started
  • Files: docs/architecture/api.md (Swagger section)

Problem: Verified against source (swaggerAuthMiddleware.ts): credentials are read from DOCS_EMAIL/DOCS_PASSWORD env vars with insecure fallbacks ([email protected] / password123). The api.md Swagger section documented these without any security callout.

Resolution: Added security warning blockquote to Swagger section in api.md: "The default credentials are insecure. Set DOCS_EMAIL and DOCS_PASSWORD environment variables before any non-local deployment. The Swagger UI exposes the full API surface." Status: RESOLVED (2026-02-12)


Finding 33 — Page count heading still says 73 (regression from Finding 22)

  • Category: D (Regression from Finding 22 fix)
  • Severity: Low
  • Status: Not started
  • Files: docs/architecture/frontend.md, docs/index.md, docs/architecture/index.md

Problem: Finding 22 claimed to update 73→~67 but the Route Map heading was missed (still said 73). Verified via glob: actual page.js/page.jsx count is 75 (5 auth + 7 public + ~40 dashboard functional + ~23 showcase). The ~67 figure used in the Finding 22 fix was also wrong. The UI Showcase section said "~30 pages" but actual count is ~23.

Resolution: Updated Route Map heading to 75 in frontend.md. Updated directory structure comment (67→75). Updated UI Showcase heading (30→23). Updated index.md (text + metadata table) and architecture/index.md to ~75. Status: RESOLVED (2026-02-12)


Finding 34 — database.md fabricates PackageCategory ↔ Package relation

  • Category: A (Doc contradiction)
  • Severity: Low
  • Status: Not started
  • Files: docs/architecture/database.md (Package + PackageCategory entities, ER diagram)

Problem: database.md showed Package with @ManyToOne(() => PackageCategory) and PackageCategory with @OneToMany(() => Package, ...). Verified against source: neither entity has this relationship. PackageCategory.ts has only basic columns (id, name, slug, timestamps). Package.ts imports PackageCategory but defines no @ManyToOne to it — only @OneToMany(() => Subscription). backend.md's (no relations) was correct all along; database.md fabricated the relation.

Resolution: Removed @ManyToOne(() => PackageCategory) from Package entity and @OneToMany(() => Package, ...) from PackageCategory entity in database.md. Removed the N:1 connection line from the ER diagram. Added note: "Package imports PackageCategory but no @ManyToOne relationship is defined in the source code." Status: RESOLVED (2026-02-12)


Finding 35 — database.md ProductCategory entity fabricated slug and isActive

  • Category: A (Doc contradiction)
  • Severity: High
  • Status: Not started
  • Files: docs/architecture/database.md (ProductCategory code block, lines ~757–776)

Problem: database.md shows ProductCategory with slug (unique) and isActive columns. Neither field exists in source. Actual ProductCategory.ts has name and description (text, nullable). description is absent from the database.md code block. backend.md (line 243) correctly lists id, name, description. Two phantom fields added, one real field omitted — same fabrication pattern as Finding 16.

Resolution: Replaced ProductCategory code block with verified source: name, description (text, nullable), timestamps. Removed phantom slug and isActive. Also fixed ER diagram (slugdescription). Status: RESOLVED (2026-02-12)


Finding 36 — database.md ER diagrams still show wrong fields for 3 entities

  • Category: A (Doc contradiction)
  • Severity: Medium
  • Status: Not started
  • Files: docs/architecture/database.md (ER diagram sections)

Problem: Finding 16 claimed to have "updated ER diagrams" but at least three entity boxes remain wrong:

Entity ER diagram shows Actual source has
InviteUser (lines 40–43) token field No token — only email and status
Coupon (lines 73–79) discount, type, expiresAt discountType, amountOff, duration (no expiresAt)
Payment (line 70) provider method (enum: stripe/paypal/lemonsqueezy)

The Payment ER diagram even contradicts its own entity code block (line 892) which correctly says method.

Resolution: Fixed all three ER diagram boxes: InviteUser removed phantom token, Coupon fields changed to discountType/amountOff/duration, Payment providermethod. Status: RESOLVED (2026-02-12)


Finding 37 — database.md Otp entity: wrong class name + silently "corrected" typo

  • Category: A (Doc contradiction)
  • Severity: Medium
  • Status: Not started
  • Files: docs/architecture/database.md (Otp code block, lines ~1177–1201)

Problem: Two issues:

  1. Class name: database.md (line 1182) says export class Otp. Actual source class name is OtpVerification (file is Otp.ts but class is OtpVerification). backend.md (line 216) correctly says OtpVerification.

  2. Column name: database.md (line 1190) shows otpHash. Actual source column is optHash — a known typo (Finding 5). Instead of documenting the actual name with [sic] (the approach used for subscribtionExpire in Finding 26, and nod_env in Finding 31), the doc silently "corrected" it. Anyone grepping the codebase for otpHash will find nothing.

Resolution: Fixed class name OtpOtpVerification in code block, entity list table, and ER diagram. Changed otpHashoptHash with [sic] annotation. Added note about file vs class name mismatch. Also fixed ER diagram entity name. Status: RESOLVED (2026-02-12)


Finding 38 — database.md missing fields in 4 entity code blocks

  • Category: A (Doc contradiction)
  • Severity: High
  • Status: Not started
  • Files: docs/architecture/database.md (BlogCategory, UserSetting, LoginAttempt, Menu code blocks)

Problem: Fields confirmed in source and listed in backend.md but absent from database.md code blocks:

Entity Missing fields Source confirms
BlogCategory serial @Column({ default: 1 }) serial: number
UserSetting tempTwoFactorSecret, language Both exist — backend.md line 209 lists them correctly
LoginAttempt isBlocked, createdAt, updatedAt, deletedAt @Column({ default: false }) isBlocked: boolean + all 3 timestamp columns
Menu locations @Column("simple-json", { nullable: true }) locations: string[] — backend.md line 248 lists it correctly

Pattern: backend.md entity summary tables are correct; database.md code blocks (supposedly the "detailed" version) are incomplete.

Resolution: Added all missing fields verified against source: BlogCategory.serial, UserSetting.tempTwoFactorSecret + language (+ fixed backupCodes type from JSON array to text), LoginAttempt.isBlocked + ManyToOne relation + all timestamps, Menu.locations (simple-json). Also removed fabricated Menu.isActive. Status: RESOLVED (2026-02-12)


Finding 39 — index.md Repository Structure still says "73 routes" and "17 domains"

  • Category: D (Regression from Findings 21/33)
  • Severity: Low
  • Status: Not started
  • Files: docs/index.md (lines 133, 135)

Problem: Finding 33 corrected the page count to ~75 in headings and text. Finding 21 corrected the API hook domain count to 16. But the Repository Structure code block in index.md was never touched:

  • Line 133: │ ├── app/ # Next.js pages (73 routes) — should be ~75
  • Line 135: │ ├── api/ # React Query hooks (17 domains) — should be 16

Resolution: Updated both code block comments in index.md: 73→~75 routes, 17→16 domains. Status: RESOLVED (2026-02-12)


Finding 40 — frontend.md directory structure says "17 domains" contradicting own heading

  • Category: D (Regression from Finding 21)
  • Severity: Low
  • Status: Not started
  • Files: docs/architecture/frontend.md (line 98 vs line 304)

Problem: frontend.md line 98: │ ├── api/ # React Query hooks (17 domains)

frontend.md line 304: **16 API hook domains**: auth, blogs, contacts, ...

Finding 21 corrected the heading and text occurrences but missed the directory structure comment. The file now contradicts itself.

Resolution: Updated frontend.md directory structure comment: 17→16 domains. Status: RESOLVED (2026-02-12)


Finding 41 — api.md POST /invite-users body shows fabricated roleId field

  • Category: A (Doc contradiction)
  • Severity: High
  • Status: Not started
  • Files: docs/architecture/api.md (lines 801–806), saas-boilerplate/src/app/modules/v1/InviteUser/invite-user.validation.ts

Problem: api.md shows:

{
  "email": "[email protected]",
  "roleId": 2
}

Verified against source: invite-user.validation.ts only accepts email (required) and status (optional enum: PENDING/ACCEPTED). No roleId field exists. Same fabrication pattern as Findings 17, 28, 29.

Resolution: Replaced POST /invite-users example with correct body (email only), added note about optional status field with enum values. Status: RESOLVED (2026-02-12)


Finding 42 — backend.md says "12 middleware files" but source has 13

  • Category: A (Doc contradiction)
  • Severity: Low
  • Status: Not started
  • Files: docs/architecture/backend.md (line 71, lines 72–83)

Problem: backend.md states # 12 middleware files and lists 12 files. Actual src/app/middlewares/ directory contains 13 files — requireStripe.ts (Stripe availability guard middleware) is missing from both the count and the listing.

Resolution: Updated count 12→13 and added requireStripe.ts to the directory listing in backend.md. Status: RESOLVED (2026-02-12)


Finding 43 — backend.md sequrity.ts not annotated with [sic] in directory listing

  • Category: D (Consistency regression from Finding 26 convention)
  • Severity: Low
  • Status: Not started
  • Files: docs/architecture/backend.md (line 80)

Problem: backend.md line 80: │ │ │ ├── sequrity.ts # Helmet security headers

This faithfully reproduces the filename typo without any [sic] annotation. Finding 26 established the convention of adding [sic] for reproduced typos (used for resetSubscribtionStatus). Finding 31 extended it to nod_env. But sequrity.ts — the most prominent typo, right in the directory structure — was never annotated.

Resolution: Added [sic] annotation to sequrity.ts line in backend.md directory listing. Status: RESOLVED (2026-02-12)


Finding 44 — database.md UserSetting twoFactorProvider enum missing sms option

  • Category: A (Doc contradiction)
  • Severity: Low
  • Status: Not started
  • Files: docs/architecture/database.md (line ~1139)

Problem: database.md comment: twoFactorProvider: TwoFactorProvider; // email | google_authenticator

Source (and backend.md line 209) shows the enum includes three options: email, google_authenticator, sms. The sms option is missing from the database.md comment.

Resolution: Added sms to the twoFactorProvider enum comment in database.md UserSetting code block. Status: RESOLVED (2026-02-12)


Finding 45 — database.md Otp entity missing createdAt and updatedAt timestamps

  • Category: A (Doc contradiction)
  • Severity: Low
  • Status: Not started
  • Files: docs/architecture/database.md (Otp code block, lines ~1182–1201)

Problem: database.md Otp code block shows only deletedAt for timestamp columns. Source has @CreateDateColumn() createdAt and @UpdateDateColumn() updatedAt as well. This same pattern affects LoginAttempt (Finding 38) — timestamp columns are systematically dropped from "internal/system" entity code blocks.

Resolution: Added createdAt and updatedAt timestamp columns to OtpVerification entity code block in database.md. Also fixed expiresAt to match source (nullable: true). Status: RESOLVED (2026-02-12)


  1. Category A first — Verify docs against source code, fix contradictions (least risk, highest doc quality impact)
  2. Category C next — Add missing sections (no code changes needed)
  3. Category B last — Code changes require careful planning, migrations, and testing

Session Log

Date Session Work Done
2026-02-12 1 Initial adversarial review completed. 15 findings documented.
2026-02-12 1 Category A resolved: Fixed 6 doc contradictions (database.md entities, api.md webhooks/rate limits/blog fields, backend.md webhook events). Expanded ER diagram to cover all 29 entities.
2026-02-12 1 Category C resolved: Added 5 missing doc sections — Node version unified to 18.17+, frontend JS acknowledged, dual charting/pkg manager documented, testing gap documented with setup guide, migration strategy documented.
2026-02-12 2 Round 3 adversarial review. 11 new findings (16–26). Major: database.md has 9+ entity code blocks with fabricated schemas (never matched source). api.md email template endpoint wrong. frontend.md table broken by blockquote. Page/domain counts off.
2026-02-12 2 Round 3 resolved: All 11 findings (16–26) fixed. database.md: 10 entity code blocks + 2 ER diagrams replaced with verified source. api.md: email template fields + swagger section added. frontend.md: table repaired, counts corrected (17→16 domains, 73→~67 pages, section headers). backend.md: date lib annotation, [sic] on typo. integration.md: httpOnly contradiction rewritten.
2026-02-12 3 Round 4 adversarial review. 8 new findings (27–34). Cross-referenced against all 26 prior findings to avoid duplicates. New: api.md has wrong fields for contacts + menu-items (same pattern as Finding 17). 8 modules completely missing from api.md. Role phantom displayName. PackageCategory relations denied. nod_env suspicious. Swagger creds no warning. Page count heading regression.
2026-02-12 3 Round 4 resolved: All 8 findings (27–34) verified against source code and fixed. database.md: Role displayName added, PackageCategory fabricated relation removed, Package→PackageCategory relation removed, ER diagram corrected, nod_env [sic] added. api.md: contacts + menu-items fields corrected, 8 missing module sections added (~37 endpoints), Swagger security warning added, Slug endpoint added. frontend.md + index.md: page counts corrected (73/~67→75, 30→23 showcase).
2026-02-12 4 Round 5 adversarial review. 11 new findings (35–45). Dominant pattern: database.md entity code blocks still not fully verified — ProductCategory fabricated (slug/isActive don't exist), 4 entities missing fields (BlogCategory.serial, UserSetting.tempTwoFactorSecret+language, LoginAttempt.isBlocked+timestamps, Menu.locations). ER diagrams still wrong for InviteUser (phantom token), Coupon (wrong fields), Payment (provider vs method). Otp entity has wrong class name and silently corrected typo. api.md invite-users has fabricated roleId. backend.md middleware count off by 1. Prior fix regressions: index.md and frontend.md still have stale "73 routes" / "17 domains" in code blocks.
2026-02-12 4 Round 5 resolved: All 11 findings (35–45) verified against source and fixed. database.md: ProductCategory rewritten (removed slug/isActive, added description), 3 ER diagrams corrected (InviteUser/Coupon/Payment), OtpVerification class name + optHash [sic] + timestamps added, BlogCategory.serial added, UserSetting.tempTwoFactorSecret+language+sms added, LoginAttempt.isBlocked+relation+timestamps added, Menu.locations added (isActive removed). api.md: invite-users roleId removed. backend.md: middleware count 12→13 + requireStripe.ts added + sequrity.ts [sic]. index.md + frontend.md: stale code block comments fixed (73→~75, 17→16).