Skip to content

Restructure website for dual-product support#17

Closed
Yuvraj-Sarathe wants to merge 33 commits into
KDM-cli:mainfrom
Yuvraj-Sarathe:Redesign
Closed

Restructure website for dual-product support#17
Yuvraj-Sarathe wants to merge 33 commits into
KDM-cli:mainfrom
Yuvraj-Sarathe:Redesign

Conversation

@Yuvraj-Sarathe
Copy link
Copy Markdown
Member

@Yuvraj-Sarathe Yuvraj-Sarathe commented May 31, 2026

Issue #14

Description

The website was originally built as a single-product site for KDM CLI only. This restructures the codebase to support multiple products under a shared ecosystem, starting with KDM CLI and Docker Guard. The architecture moves from hardcoded product content to a config-driven system, reorganizes routing around product hubs, and introduces a React context for dynamic branding across all shared components.


Changes:

  1. Config System (src/config/products/)

    • Defined TypeScript interfaces for all product metadata (types.ts): ProductConfig, ProductFeature, ProductCommand, ProductStat, TerminalLine, ProductMetadata
    • Created full configuration objects for KDM CLI (kdm.ts) and Docker Guard (docker-guard.ts) covering branding, features, commands, stats, and terminal demo content
    • Added a product registry (index.ts) with getProductBySlug() resolver and default product fallback
  2. Product Context (src/context/ProductContext.tsx)

    • New ProductProvider component wrapping route subtrees with product configuration
    • useProduct() hook for any component to access current product config
    • Wired into __root.tsx at the top level with slug derived from route matching Routing (src/routes/)
    • Converted index.tsx from KDM landing page to a product-selection hub
    • Created layout routes (kdm.tsx, docker-guard.tsx) that provide product context for each sub-tree
    • Restructured doc routes under each product: kdm.docs.tsx, kdm.docs.index.tsx, kdm.docs.$slug.tsx and equivalent for Docker Guard
    • Removed flat docs.tsx, docs.index.tsx, docs.$slug.tsx in favor of namespaced variants
      Components (src/components/)
    • All landing components (Navbar, Footer, Hero, Terminal, Features, Commands, CTA) now consume useProduct() for dynamic, config-driven content
    • Fixed broken CTA buttons (had href="#") and corrected footer "Status" link target
      Documentation (src/docs/)
    • Moved existing KDM docs into src/docs/kdm/ subdirectory
    • Created src/docs/docker-guard/ with placeholder files
    • Refactored src/lib/docs.ts into createDocLoader(product) factory function

Route Map

Old URL New URL
/ (KDM landing) / (product hub)
/kdm/
/docs /kdm/docs
/docs/:slug /kdm/docs/:slug
/docker-guard/
/docker-guard/docs
/docker-guard/docs/:slug

Remaining Work:

  • Replace src/assets/docker-guard-logo.png with a proper logo
  • Write substantive documentation content in src/docs/docker-guard/*.md
  • Review and finalize Docker Guard landing page wireframes

Summary by CodeRabbit

  • New Features

    • Added Docker Guard CLI as a new product alongside KDM.
    • Created an ecosystem hub page showcasing both available CLI products.
    • Implemented product-specific landing pages and documentation.
  • Documentation

    • Added Docker Guard installation guide and command reference.
    • Reorganized documentation structure for product-specific content.
  • Chores

    • Added unenv as a runtime dependency.
    • Updated ignore patterns for documentation directories and generated artifacts.

- Changed title from 'Lovable App' to 'KDM Ecosystem'
- Updated description to ecosystem-neutral content
- Removed 'author: Lovable' meta tag
- Updated OG/twitter metadata to KDM Ecosystem
- Removed twitter:site @lovable reference
…g types

- ProductFeature with icon (string), title, desc, cmd
- ProductCommand with name, sig, desc, output
- ProductStat with value, label
- TerminalLine with optional prompt, out, blink
- ProductMetadata for SEO/OG fields
- ProductConfig combining all of the above
- Full ProductConfig with exact content from existing components
- 6 features with Lucide icon names, 4 commands, 3 stats
- 9 terminal lines matching Terminal.tsx
- Metadata for SEO, CTA content, copyright
- Full ProductConfig with Docker Guard branding
- 6 features (Shield, Eye, HeartPulse, Radio, ScrollText, Cloud)
- 4 commands (guard, ps, health, events) with terminal output
- 3 stats for container monitoring
- 10 terminal lines with dg commands and output
- products array with kdm and dockerGuard configs
- getProductBySlug lookup function
- defaultProduct fallback export (kdm)
- 00-01-SUMMARY.md: root metadata fix results
- 01-01-SUMMARY.md: product config system results
- ROADMAP.md: mark both Wave 1 plans as complete
…seProduct hook

- ProductProvider accepts optional slug prop, validates against registry
- useProduct hook returns current ProductConfig (never undefined)
- Falls back to default product (kdm) when slug is missing or unknown
- Wrap Outlet in ProductProvider in RootComponent
- Default product (kdm) is used until route-specific layouts pass a slug
- 01-02-SUMMARY.md with execution details and Wave 3 guidance
- ROADMAP.md: mark 01-02 as completed
- Replaced hardcoded 'kdm' brand name with product.brandName
- Replaced /docs Link with dynamic <a href={product.docsPath}>
- Replaced hardcoded GitHub URLs with product.githubUrl
- Both desktop and mobile Sheet docs/GitHub links are now product-aware
- Added import * as LucideIcons for dynamic icon resolution
- Added useProduct hook to consume product config
- Removed hardcoded features array
- Features grid now driven by product.features from ProductContext
- Dynamic heading Built for {product.displayName}
- Icons resolved from string names via LucideIcons lookup
- Replaced hardcoded 'kdm' brand text with product.brandName
- Replaced hardcoded copyright with product.copyright
- Replaced hardcoded GitHub URLs with product.githubUrl (Status + GitHub links)
- Privacy and Terms links remain root-level unchanged
…hook

- Add useProduct import from ProductContext
- Replace hardcoded version badge with product.version
- Replace hardcoded headline with product.displayName
- Replace hardcoded tagline with product.tagline
- Replace hardcoded description with product.description
- Replace hardcoded install command with product.installCommand
- Replace hardcoded stats grid with product.stats.map()
- Replace hardcoded CTA button with product.ctaPrimaryText
- Replace hardcoded GitHub URL with product.githubUrl
- Added useProduct hook to consume product config
- Removed hardcoded commands array
- Command tabs now driven by product.commands from ProductContext
- Dynamic heading {product.displayName} commands
- All existing layout, tab UI, and terminal output styling preserved
…uct hook

- Add useProduct import from ProductContext
- Remove hardcoded module-level lines array
- Replace hardcoded terminal lines with product.terminalLines
- Replace timer setup to iterate over product.terminalLines
- Replace hardcoded title with product.brandName
- Navbar: brandName, docsPath, githubUrl now from ProductContext
- Footer: brandName, copyright, githubUrl now from ProductContext
- Updated ROADMAP.md to mark Phase 3 complete
- Added useProduct hook to consume product config
- Replaced hardcoded Ship. with product.ctaTagline
- Replaced hardcoded description with product.ctaDescription
- Replaced Start Now button with product.ctaPrimaryText
- Replaced Link to /docs with <a> using product.docsPath
- Removed unused @tanstack/react-router Link import
- All existing layout, CSS classes, and responsive sizing preserved
…plan

- Add SUMMARY.md documenting all changes
- Update ROADMAP.md to mark 04a-01 plan as complete
- Added SUMMARY.md documenting all changes, decisions, and deviations
- Created STATE.md tracking execution position and accumulated decisions
- Updated ROADMAP.md marking 04b-01 as completed
- Replace single-product KDM landing page with hub page at /
- Show both KDM and Docker Guard product cards with stats
- Inline footer with links to /privacy and /terms
- Remove imports of Navbar, Hero, Features, Commands, CTA, Footer
- HubPage component renders selection gateway
- kdm.tsx: layout route at /kdm with ProductProvider slug='kdm'
- docker-guard.tsx: layout route at /docker-guard with ProductProvider slug='docker-guard'
- Both routes wrap children in correct ProductContext
- TanStack Router auto-registers both routes in generated tree
- unenv is a transitive dependency needed by nitro build
- docs/ added to gitignore (build output directory)
- SUMMARY.md created with execution details
- STATE.md updated with completed plan and session info
- ROADMAP.md marks 02a-01 as completed
- src/routes/kdm.index.tsx — kdm landing page with Navbar, Hero, Features, Commands, CTA, Footer
- src/routes/docker-guard.index.tsx — Docker Guard landing page with same structure
- Both pages render inside the product layout Outlets created in 02a-01
- Head metadata sourced from product config for proper OG tags
- SUMMARY.md documenting all changes
- STATE.md updated with completion status and plan tracking
- ROADMAP.md updated with 02a-02 marked complete
… doc loader

- Create src/docs/kdm/ with kdm-cli documentation files
- Create src/docs/docker-guard/ with Docker Guard documentation files
- Remove old flat doc files from src/docs/
- Refactor src/lib/docs.ts: add createDocLoader(product) factory function
- Update all 6 product doc route files to use createDocLoader
- Fix .gitignore to only ignore root-level docs/ not src/docs/
…ting through unknown

The cast from typeof LucideIcons to Record<string, ComponentType<...>>
failed because lucide-react icons use ForwardRefExoticComponent which
isn't directly assignable to ComponentType. Fixed by casting through
unknown first.
- Hero primary CTA: href='#' → product.docsPath

- CTA section primary CTA: href='#' → product.githubUrl

- Footer 'Status' → 'Issues' linking to GitHub issues page
- Added .planning/ and REVIEW-FIX.md to .gitignore

- Removed 21 planning artifacts and 1 review artifact from tracking
@vercel
Copy link
Copy Markdown

vercel Bot commented May 31, 2026

@Yuvraj-Sarathe is attempting to deploy a commit to the utkarsh232005's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 31, 2026

Review Change Stack

Warning

Review limit reached

@Yuvraj-Sarathe, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 21 minutes and 4 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b6f1c45-bbec-4441-8584-8a6e30ea4bd0

📥 Commits

Reviewing files that changed from the base of the PR and between f5825a7 and aae3841.

⛔ Files ignored due to path filters (2)
  • bun.lock is excluded by !**/*.lock
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (24)
  • .all-contributorsrc
  • .github/labeler.yml
  • .github/workflows/pr.yml
  • .github/workflows/review-labels.yml
  • .gitignore
  • CONTRIBUTING.md
  • README.md
  • package.json
  • src/components/CTA.tsx
  • src/components/Commands.tsx
  • src/components/Features.tsx
  • src/components/Footer.tsx
  • src/components/Hero.tsx
  • src/components/Navbar.tsx
  • src/components/Terminal.tsx
  • src/context/ProductContext.tsx
  • src/lib/docs.ts
  • src/routes/__root.tsx
  • src/routes/docker-guard.docs.tsx
  • src/routes/index.tsx
  • src/routes/kdm.docs.tsx
  • src/server.ts
  • src/styles.css
  • src/tanstack-react-start.d.ts
📝 Walkthrough

Walkthrough

This PR migrates the KDM website from a single hardcoded product to a configurable multi-product ecosystem. A new product configuration system, React context provider, and parameterized doc loader enable dynamic product-specific rendering. Routes reorganize under product paths (/kdm, /docker-guard), components consume product context, and the home page becomes an ecosystem hub.

Changes

Multi-product ecosystem refactor

Layer / File(s) Summary
Product configuration types and data
src/config/products/types.ts, src/config/products/kdm.ts, src/config/products/docker-guard.ts, src/config/products/index.ts
New ProductConfig schema defines product identity, features, commands, stats, terminal lines, and metadata. KDM and Docker Guard products are configured and registered with a default product and lookup helper.
Product context and provider
src/context/ProductContext.tsx
ProductContext is initialized with a default product, resolveConfig helper selects products by slug, ProductProvider wraps routes to supply the resolved config, and useProduct hook exposes it to components.
Product-scoped documentation loader
src/lib/docs.ts, src/docs/docker-guard/index.md, src/docs/docker-guard/commands.md, src/docs/docker-guard/installation.md, src/docs/kdm/index.md
Doc loading refactored from module-level glob to parameterized createDocLoader(product) that selects KDM or Docker Guard sources. Docker Guard docs added; KDM docs directory structure updated.
Components consume product context
src/components/CTA.tsx, src/components/Commands.tsx, src/components/Features.tsx, src/components/Footer.tsx, src/components/Hero.tsx, src/components/Navbar.tsx, src/components/Terminal.tsx
CTA, Commands, Features, Footer, Hero, Navbar, and Terminal components refactored to source product-specific copy, icons, links, metrics, and commands from useProduct() instead of hardcoded values.
Root layout and route tree foundation
src/routes/__root.tsx, src/routeTree.gen.ts
Root layout wraps all routes with ProductProvider; head metadata updated to "KDM Ecosystem." Generated route tree replaces /docs routes with product-specific /kdm and /docker-guard branches, including updated type exports and TanStack Router module augmentation.
KDM product routes
src/routes/kdm.tsx, src/routes/kdm.index.tsx, src/routes/kdm.docs.tsx, src/routes/kdm.docs.index.tsx, src/routes/kdm.docs.$slug.tsx
KDM routes implement /kdm, /kdm/docs, and /kdm/docs/$slug with ProductProvider wrapping (slug="kdm"), KDM-scoped doc loader integration, and composed landing-page and doc layouts.
Docker Guard product routes
src/routes/docker-guard.tsx, src/routes/docker-guard.index.tsx, src/routes/docker-guard.docs.tsx, src/routes/docker-guard.docs.index.tsx, src/routes/docker-guard.docs.$slug.tsx
Docker Guard routes implement /docker-guard, /docker-guard/docs, and /docker-guard/docs/$slug with ProductProvider wrapping (slug="docker-guard"), Docker Guard-scoped doc loader, and analogous landing and doc layouts.
Home page ecosystem hub redesign
src/routes/index.tsx
Home page redesigned as ecosystem hub with new StatsRow (product metrics grid) and ProductCard (product link cards) components. HubPage renders two product cards (KDM and Docker Guard) linking to product-specific pages, replacing the prior hero-based home layout.
Dependencies and configuration
.gitignore, package.json
Added unenv (^2.0.0-rc.24) dependency. Extended .gitignore to exclude package-lock.json, /docs/, .planning/, and REVIEW-FIX.md.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 A hop, skip, and a jump through the ecosystem we've grown,
Two products now share the spotlight, never alone!
With context and config, the path is now clear,
Dynamic by nature—let multiple products cheer! 🚀✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main objective of the changeset: restructuring the website to support multiple products instead of a single KDM product.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

codescene-delta-analysis[bot]

This comment was marked as outdated.

- Removed package-lock.json from .gitignore (was blocking npm ci in CI)

- Added bun.lock to .gitignore (project uses npm)

- CI runs npm ci which requires a lockfile — bun.lock is not compatible
codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/routes/kdm.docs.index.tsx (1)

5-23: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Sanitize marked HTML before rendering to prevent XSS
src/lib/docs.ts sets html: marked.parse(body, ...) and src/components/docs/DocView.tsx renders it via dangerouslySetInnerHTML; marked doesn’t sanitize raw HTML by default, so any HTML in the markdown will execute in the browser. Sanitize the HTML (e.g., DOMPurify) in the loader (centralized for both /kdm/docs/ and /kdm/docs/$slug) before setting doc.html.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/routes/kdm.docs.index.tsx` around lines 5 - 23, The generated HTML from
marked in the docs loader (created by createDocLoader and returned via getDoc)
is not being sanitized before being stored/served, so update the loader logic in
the function that assigns doc.html (the code in src/lib/docs.ts used by
createDocLoader) to run the marked.parse output through a sanitizer (e.g.,
DOMPurify) before setting doc.html; ensure the sanitized HTML is what
KdmDocsIndex (which calls getDoc("")) and the DocView component receive and
render via dangerouslySetInnerHTML so raw HTML cannot execute in the browser.
🧹 Nitpick comments (6)
src/config/products/types.ts (1)

44-47: ⚡ Quick win

Mark config collections as readonly.

These product configs are effectively shared singletons. Mutable arrays keep accidental in-place edits type-safe today, which would leak across every subtree consuming the same context value.

Proposed direction
 export interface ProductConfig {
   slug: ProductSlug;
   displayName: string;
   brandName: string;
   tagline: string;
   description: string;
   version: string;
   installCommand: string;
   githubUrl: string;
   docsPath: string;
-  features: ProductFeature[];
-  commands: ProductCommand[];
-  stats: ProductStat[];
-  terminalLines: TerminalLine[];
+  readonly features: readonly ProductFeature[];
+  readonly commands: readonly ProductCommand[];
+  readonly stats: readonly ProductStat[];
+  readonly terminalLines: readonly TerminalLine[];
   ctaTagline: string;
   ctaDescription: string;
   ctaPrimaryText: string;
   metadata: ProductMetadata;
   copyright: string;

Also applies to: 34-53

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/config/products/types.ts` around lines 44 - 47, The product config
exposes mutable arrays (features, commands, stats, terminalLines and other
collection properties in the same block around lines 34–53) which allows
in-place edits to leak across consumers; change those types to readonly
collections (e.g. use readonly ProductFeature[] or ReadonlyArray<ProductFeature>
for features, readonly ProductCommand[] for commands, readonly ProductStat[] for
stats, readonly TerminalLine[] for terminalLines, and likewise replace any other
mutable array types in that interface/type) so the config is treated as an
immutable/shared singleton; update the exported type declarations in
src/config/products/types.ts accordingly.
src/context/ProductContext.tsx (1)

13-19: ⚡ Quick win

Fix Prettier formatting.

Static analysis detected formatting inconsistencies. Run Prettier to align the code with the project's formatting rules.

npx prettier --write src/context/ProductContext.tsx

Also applies to: 21-23

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/context/ProductContext.tsx` around lines 13 - 19, The ProductProvider
component signature has Prettier formatting inconsistencies; run the project's
Prettier formatter (e.g., npx prettier --write) on the file and reformat the
function declaration around ProductProvider and the adjacent prop/type lines
(the slug?: string; children: ReactNode; block) so they match project style;
ensure consistent spacing, commas, and braces to resolve the static analysis
warnings.
src/config/products/docker-guard.ts (1)

50-50: 💤 Low value

Clarify the "cloud · auto" command pattern.

The cmd value "cloud · auto" at line 50 differs from the CLI command patterns used elsewhere (e.g., "dg guard", "dg ps"). If this indicates a feature not yet exposed via CLI or requires special UI rendering, consider adding a comment or adjusting the value to match the established pattern for consistency.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/config/products/docker-guard.ts` at line 50, The cmd value "cloud · auto"
in the product config (the cmd property for the Docker-guard product) is
inconsistent with other CLI patterns like "dg guard" and "dg ps" — either
replace it with the canonical CLI token (e.g., "dg cloud" or "dg auto" per
product behavior) or add an inline comment next to the cmd property explaining
that this is a UI-only display string and not a real CLI command; update the cmd
property in the same object where cmd is defined (look for the Docker-guard
product entry) and ensure any consumer expecting CLI tokens uses the canonical
token instead of the current display string.
src/config/products/index.ts (1)

6-8: ⚡ Quick win

Add explicit return type annotation.

The getProductBySlug function implicitly returns ProductConfig | undefined, but an explicit annotation improves type clarity and prevents accidental type widening.

📘 Proposed fix
+import type { ProductConfig } from "./types";
+
-export function getProductBySlug(slug: string) {
+export function getProductBySlug(slug: string): ProductConfig | undefined {
   return products.find((p) => p.slug === slug);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/config/products/index.ts` around lines 6 - 8, Add an explicit return type
to getProductBySlug: change its signature to return ProductConfig | undefined so
the function getProductBySlug(slug: string): ProductConfig | undefined { ... }
is explicit; locate the function in src/config/products/index.ts and annotate
the return type using the existing ProductConfig type (import it if necessary).
src/components/Terminal.tsx (1)

8-13: ⚡ Quick win

Rerun the animation when product.terminalLines changes.

This effect closes over product.terminalLines, but the empty dependency array means the typewriter sequence won't restart if the product context changes. Reset visible and include a stable product/lines dependency so the terminal stays in sync with the selected product.

Suggested fix
   useEffect(() => {
+    setVisible(0);
     const timers = product.terminalLines.map((_, i) =>
       setTimeout(() => setVisible((v) => Math.max(v, i + 1)), 300 + i * 280)
     );
     return () => timers.forEach(clearTimeout);
-  }, []);
+  }, [product.terminalLines]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Terminal.tsx` around lines 8 - 13, The effect in useEffect
that schedules timeouts for product.terminalLines currently has an empty
dependency array so it won’t restart when product.terminalLines changes; update
the effect that creates timers (the useEffect block referencing
product.terminalLines, timers, setVisible) to depend on the lines (e.g.,
product.terminalLines or a stable key like product.id or serialized lines) and
inside the effect reset visible to 0 (or the initial value) before scheduling,
clear any existing timeouts in the cleanup, and then schedule new timeouts so
the typewriter sequence restarts whenever the product/lines change.
src/components/Commands.tsx (1)

5-7: ⚡ Quick win

Downgrade: no current crash path, but add a defensive guard

In this app, src/components/Commands.tsx is mounted under route-level ProductProvider instances with a fixed slug (/kdm or /docker-guard), and active is only set from the current product.commands.map((_, i) => ...) indices—so product.commands[active] should be defined with the current config. Still, a small guard (and optional clamping if ProductContext ever becomes dynamic or commands can be empty) would prevent future render-time crashes when configs change.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Commands.tsx` around lines 5 - 7, The code directly indexes
product.commands with product.commands[active] (variables: active, setActive,
useProduct, product, product.commands, cmd) which can crash if commands is empty
or active is out of range; add a defensive guard: ensure product.commands exists
and has length > 0 before indexing, clamp active to [0, product.commands.length
- 1] (or default to 0), and compute cmd only when safe (e.g., const cmd =
product.commands?.[clampedActive] ?? undefined) so renders won't throw if the
product context changes or commands becomes empty.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@package.json`:
- Line 67: The package.json currently lists the prerelease "unenv"
(^2.0.0-rc.24) as a production dependency but there’s no usage in source; either
move "unenv" to devDependencies if it’s only build/test/tooling, remove it
entirely if unused, or pin it to the stable release ("unenv" 1.10.0) if you
truly need it in production; locate the "unenv" entry in package.json and update
the dependency section accordingly and confirm no runtime imports reference
unenv before changing.

In `@src/components/CTA.tsx`:
- Around line 19-21: The CTA component currently uses a plain <a> to navigate to
product.docsPath which prevents TanStack Router client-side transitions; replace
the anchor with the TanStack Router <Link> (import { Link } from
'`@tanstack/router`') and render <Link to={product.docsPath} className="btn-mono
...">Read the docs</Link>, keeping the same className and children; if
product.docsPath can be external (startsWith 'http'), add a small conditional to
fall back to an <a> with target/_blank, otherwise use <Link> for internal
routing.

In `@src/components/Features.tsx`:
- Around line 1-2: The code currently namespace-imports all icons as LucideIcons
and uses runtime lookup LucideIcons[f.icon] in Features.tsx which prevents
tree-shaking and increases bundle size; replace that pattern by either creating
a small explicit registry mapping the expected icon names (the f.icon values) to
individually imported icon components and use that map in the Icon selection, or
import Lucide’s dynamic renderer (DynamicIcon from "lucide-react/dynamic") and
pass the f.icon name to it; update the Icon lookup logic to use the registry key
or DynamicIcon instead of LucideIcons[f.icon] and remove the namespace import to
ensure per-icon imports are tree-shakeable.

In `@src/components/Hero.tsx`:
- Around line 9-12: The copy handler currently calls
navigator.clipboard.writeText(product.installCommand) without awaiting or
handling rejection and sets setCopied(true) immediately; change the copy
function (copy) to await or use .then/.catch on navigator.clipboard.writeText
and only call setCopied(true) after the writeText promise resolves, handle
errors in the .catch (e.g., set an error state or log via console.error) and
ensure you don't leave an unhandled rejection; also if the click handler is a
prop, make it async or return the promise so the component's event flow remains
correct.

In `@src/components/Navbar.tsx`:
- Line 25: The desktop and mobile "Docs" anchors using product.docsPath are
internal TanStack Router routes and cause full page reloads; in Navbar (replace
the <a href={product.docsPath}> instances including the mobile variant), and
likewise in Hero and CTA where product.docsPath is used, swap the anchor tags
for the TanStack Router Link component and use the to={product.docsPath} prop so
navigation is SPA-friendly; ensure you import Link from the router at the top of
each component (e.g., Navbar, Hero, CTA) and preserve existing className and
children when replacing the tag.

In `@src/config/products/types.ts`:
- Around line 34-43: Replace the plain string for ProductConfig.slug with a
shared literal union type: define and export a single source of truth (e.g., a
const array like PRODUCT_SLUGS = ['foo','bar'] as const and a type ProductSlug =
typeof PRODUCT_SLUGS[number] or an exported enum) in this module, change the
interface to use slug: ProductSlug, and update all other modules that currently
accept or construct slug values to import and use ProductSlug (or PRODUCT_SLUGS)
so typos fail at compile time rather than runtime; keep the symbol
ProductConfig.slug as the consumer-facing property name.

In `@src/context/ProductContext.tsx`:
- Around line 13-24: ProductProvider currently calls resolveConfig(slug) on
every render which creates a new config object and may trigger unnecessary
re-renders of consumers; wrap the resolveConfig(slug) call in React.useMemo so
the config is recomputed only when slug changes, keeping the same reference
across renders, e.g. memoize the value used for ProductContext.Provider (the
resolved config passed into ProductContext.Provider) and list slug as the
dependency.

In `@src/lib/docs.ts`:
- Around line 49-59: The frontmatter "order" parsing uses Number(data.order)
which can yield NaN and break the sort in the .sort comparator; update the
mapping where parseFrontmatter is used (the object with slug, title, order,
html) to coerce and validate the order value (e.g., use Number(data.order) only
if Number.isFinite(...) or fallback to 999) so that the order property on each
doc is always a finite number, keeping parseFrontmatter/data.order handling
robust and preserving the existing sort call that uses a.order - b.order ||
a.title.localeCompare(b.title).

In `@src/routes/index.tsx`:
- Around line 68-70: Prettier wants the JSX props and inline text condensed onto
single lines; update the paragraph and similar blocks so the element and its
text are on one line (e.g., change <p className="text-sm text-foreground/50">
Choose your tool </p> to <p className="text-sm text-foreground/50">Choose your
tool</p>) and apply the same single-line formatting to the other affected JSX
blocks around the code that spans lines 84-95.
- Around line 42-44: Prettier wants the JSX text content on a single line:
collapse the multiline <p> element that renders product.description into a
single-line JSX expression by keeping the same className and content but placing
the opening tag, the {product.description} expression, and the closing tag on
one line (locate the JSX that uses product.description in the <p
className="text-sm text-foreground/50 mb-6 leading-relaxed"> element and
reformat it to a single line).
- Line 56: The current array destructuring "const [kdmProduct,
dockerGuardProduct] = products" is fragile; replace it with explicit lookups
(e.g., find product where product.slug === 'kdm' and product.slug ===
'docker-guard') so the mapping is explicit and order-independent, assign those
results to kdmProduct and dockerGuardProduct, and add a fail-fast check (throw
or processLogger/error) if either lookup returns undefined so the page fails
loudly when a product is missing.

---

Outside diff comments:
In `@src/routes/kdm.docs.index.tsx`:
- Around line 5-23: The generated HTML from marked in the docs loader (created
by createDocLoader and returned via getDoc) is not being sanitized before being
stored/served, so update the loader logic in the function that assigns doc.html
(the code in src/lib/docs.ts used by createDocLoader) to run the marked.parse
output through a sanitizer (e.g., DOMPurify) before setting doc.html; ensure the
sanitized HTML is what KdmDocsIndex (which calls getDoc("")) and the DocView
component receive and render via dangerouslySetInnerHTML so raw HTML cannot
execute in the browser.

---

Nitpick comments:
In `@src/components/Commands.tsx`:
- Around line 5-7: The code directly indexes product.commands with
product.commands[active] (variables: active, setActive, useProduct, product,
product.commands, cmd) which can crash if commands is empty or active is out of
range; add a defensive guard: ensure product.commands exists and has length > 0
before indexing, clamp active to [0, product.commands.length - 1] (or default to
0), and compute cmd only when safe (e.g., const cmd =
product.commands?.[clampedActive] ?? undefined) so renders won't throw if the
product context changes or commands becomes empty.

In `@src/components/Terminal.tsx`:
- Around line 8-13: The effect in useEffect that schedules timeouts for
product.terminalLines currently has an empty dependency array so it won’t
restart when product.terminalLines changes; update the effect that creates
timers (the useEffect block referencing product.terminalLines, timers,
setVisible) to depend on the lines (e.g., product.terminalLines or a stable key
like product.id or serialized lines) and inside the effect reset visible to 0
(or the initial value) before scheduling, clear any existing timeouts in the
cleanup, and then schedule new timeouts so the typewriter sequence restarts
whenever the product/lines change.

In `@src/config/products/docker-guard.ts`:
- Line 50: The cmd value "cloud · auto" in the product config (the cmd property
for the Docker-guard product) is inconsistent with other CLI patterns like "dg
guard" and "dg ps" — either replace it with the canonical CLI token (e.g., "dg
cloud" or "dg auto" per product behavior) or add an inline comment next to the
cmd property explaining that this is a UI-only display string and not a real CLI
command; update the cmd property in the same object where cmd is defined (look
for the Docker-guard product entry) and ensure any consumer expecting CLI tokens
uses the canonical token instead of the current display string.

In `@src/config/products/index.ts`:
- Around line 6-8: Add an explicit return type to getProductBySlug: change its
signature to return ProductConfig | undefined so the function
getProductBySlug(slug: string): ProductConfig | undefined { ... } is explicit;
locate the function in src/config/products/index.ts and annotate the return type
using the existing ProductConfig type (import it if necessary).

In `@src/config/products/types.ts`:
- Around line 44-47: The product config exposes mutable arrays (features,
commands, stats, terminalLines and other collection properties in the same block
around lines 34–53) which allows in-place edits to leak across consumers; change
those types to readonly collections (e.g. use readonly ProductFeature[] or
ReadonlyArray<ProductFeature> for features, readonly ProductCommand[] for
commands, readonly ProductStat[] for stats, readonly TerminalLine[] for
terminalLines, and likewise replace any other mutable array types in that
interface/type) so the config is treated as an immutable/shared singleton;
update the exported type declarations in src/config/products/types.ts
accordingly.

In `@src/context/ProductContext.tsx`:
- Around line 13-19: The ProductProvider component signature has Prettier
formatting inconsistencies; run the project's Prettier formatter (e.g., npx
prettier --write) on the file and reformat the function declaration around
ProductProvider and the adjacent prop/type lines (the slug?: string; children:
ReactNode; block) so they match project style; ensure consistent spacing,
commas, and braces to resolve the static analysis warnings.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3014d05f-7c0e-4392-b0cf-7cacdea34f34

📥 Commits

Reviewing files that changed from the base of the PR and between 2918477 and f5825a7.

⛔ Files ignored due to path filters (1)
  • src/assets/docker-guard-logo.png is excluded by !**/*.png
📒 Files selected for processing (35)
  • .gitignore
  • package.json
  • src/components/CTA.tsx
  • src/components/Commands.tsx
  • src/components/Features.tsx
  • src/components/Footer.tsx
  • src/components/Hero.tsx
  • src/components/Navbar.tsx
  • src/components/Terminal.tsx
  • src/config/products/docker-guard.ts
  • src/config/products/index.ts
  • src/config/products/kdm.ts
  • src/config/products/types.ts
  • src/context/ProductContext.tsx
  • src/docs/docker-guard/commands.md
  • src/docs/docker-guard/index.md
  • src/docs/docker-guard/installation.md
  • src/docs/kdm/commands.md
  • src/docs/kdm/contributing.md
  • src/docs/kdm/index.md
  • src/docs/kdm/installation.md
  • src/lib/docs.ts
  • src/routeTree.gen.ts
  • src/routes/__root.tsx
  • src/routes/docker-guard.docs.$slug.tsx
  • src/routes/docker-guard.docs.index.tsx
  • src/routes/docker-guard.docs.tsx
  • src/routes/docker-guard.index.tsx
  • src/routes/docker-guard.tsx
  • src/routes/index.tsx
  • src/routes/kdm.docs.$slug.tsx
  • src/routes/kdm.docs.index.tsx
  • src/routes/kdm.docs.tsx
  • src/routes/kdm.index.tsx
  • src/routes/kdm.tsx

Comment thread package.json
Comment thread src/components/CTA.tsx Outdated
Comment thread src/components/Features.tsx
Comment thread src/components/Hero.tsx
Comment thread src/components/Navbar.tsx Outdated
Comment thread src/context/ProductContext.tsx Outdated
Comment thread src/lib/docs.ts
Comment thread src/routes/index.tsx Outdated
Comment thread src/routes/index.tsx
Comment thread src/routes/index.tsx Outdated
- unstorage (dep of @lovable.dev/vite-tanstack-config) has lru-cache@^11.2.6 as optional peer

- npm 11 (local) skips optional peers in lockfile, but npm 10 (CI on Node.js 20) requires them

- Adding lru-cache directly as optionalDependency ensures lockfile parity
codescene-delta-analysis[bot]

This comment was marked as outdated.

- Auto-fixed by Prettier 3.7.3

- Addresses CI lint failure: improper line breaks, indentation, quotes, whitespace in JSX
codescene-delta-analysis[bot]

This comment was marked as outdated.

codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown

@codescene-delta-analysis codescene-delta-analysis Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our agent can fix these. Install it.

Gates Passed
3 Quality Gates Passed

Absence of Expected Change Pattern

  • kdm-website/src/components/Hero.tsx is usually changed with: kdm-website/vite.config.ts

Quality Gate Profile: The Bare Minimum
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.

@Yuvraj-Sarathe
Copy link
Copy Markdown
Member Author

Yuvraj-Sarathe commented May 31, 2026

The one test this PR is failing has been addressed in #18

So merge this PR @utkarsh232005

@vercel
Copy link
Copy Markdown

vercel Bot commented May 31, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
kdm-website Ready Ready Preview, Comment May 31, 2026 12:23pm

@utkarsh232005
Copy link
Copy Markdown
Member

Hey @Yuvraj-Sarathe, thanks for the effort on this restructuring!

Right now, this changes the root route (/) into a product selection page. We actually want to keep the current website structure and UI exactly as it is for the main landing page.

Instead of an ecosystem hub at the root, let's integrate the new products directly into the existing Navbar using a dropdown menu (e.g., "Products" or "Tools"). When a user clicks it, they should see the other tools listed—like KDC—and clicking a tool will redirect them to its respective webpage.

@Yuvraj-Sarathe
Copy link
Copy Markdown
Member Author

Hey @Yuvraj-Sarathe, thanks for the effort on this restructuring!

Right now, this changes the root route (/) into a product selection page. We actually want to keep the current website structure and UI exactly as it is for the main landing page.

Instead of an ecosystem hub at the root, let's integrate the new products directly into the existing Navbar using a dropdown menu (e.g., "Products" or "Tools"). When a user clicks it, they should see the other tools listed—like KDC—and clicking a tool will redirect them to its respective webpage.

so what to do with this PR?

@utkarsh232005
Copy link
Copy Markdown
Member

Hey @Yuvraj-Sarathe, thanks for the effort on this restructuring!
Right now, this changes the root route (/) into a product selection page. We actually want to keep the current website structure and UI exactly as it is for the main landing page.
Instead of an ecosystem hub at the root, let's integrate the new products directly into the existing Navbar using a dropdown menu (e.g., "Products" or "Tools"). When a user clicks it, they should see the other tools listed—like KDC—and clicking a tool will redirect them to its respective webpage.

so what to do with this PR?

you can close this pr and create fresh pr with the required changes

@Yuvraj-Sarathe
Copy link
Copy Markdown
Member Author

Hey @Yuvraj-Sarathe, thanks for the effort on this restructuring!
Right now, this changes the root route (/) into a product selection page. We actually want to keep the current website structure and UI exactly as it is for the main landing page.
Instead of an ecosystem hub at the root, let's integrate the new products directly into the existing Navbar using a dropdown menu (e.g., "Products" or "Tools"). When a user clicks it, they should see the other tools listed—like KDC—and clicking a tool will redirect them to its respective webpage.

so what to do with this PR?

you can close this pr and create fresh pr with the required changes

I don't think I can spare time for such task now because my college is restarting from tomorrow so please assign someone else

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat: Redesign website to support dual-product architecture and documentation

2 participants