gotekna avatar

duplicate-detector

Detects duplicate implementations, SSoT violations, and banned patterns. Use before any code change

作者 gotekna|オープンソース

Duplicate Detector

Note: This skill focuses on finding duplicated code patterns and SSoT violations. For Rails method validation (NoMethodError prevention), see the method-auditor agent.

When Claude Should Use This

  • Adding a new constant or config value
  • Implementing business logic
  • Creating a new component or service
  • Adding environment variables
  • Defining routes or endpoints
  • Adding UI features (fullscreen, loading states, modals)
  • Before writing any new code - check if pattern exists

Process

Step 1: Check Component Registry FIRST

# Always check if component/pattern exists in registry
grep -i "FEATURE_NAME" frontend-next/lib/component-registry.ts

Step 2: Search for Existing Implementations

# Search both frontend and backend
grep -ri "SEARCH_TERM" backend/ frontend-next/ --include="*.rb" --include="*.ts" --include="*.tsx" --include="*.yml" --include="*.json" | grep -v node_modules | head -20

Step 3: If Found in Multiple Places

  1. List all locations with file:line
  2. Show the user both implementations
  3. Ask: "Which is the source of truth?"
  4. Wait for user response
  5. Consolidate to one location after user confirms

Step 4: If Not Found

  • Proceed with implementation
  • Add to SSoT component if it's a reusable pattern
  • Register in component-registry.ts if new component

UI Component SSoT Checks

Run These Before ANY UI Work

1. Lucide Loader Violations (Should use Spinner)

echo "=== LUCIDE LOADER VIOLATIONS ==="
grep -rn "Loader.*from.*lucide-react\|from.*lucide-react.*Loader" frontend-next/app frontend-next/components --include="*.tsx" | grep -v "spinner.tsx"

Fix: Replace with import { Spinner } from "@/components/ui/spinner"

2. router.back() Violations (Should use BackButton)

echo "=== ROUTER.BACK() VIOLATIONS ==="
grep -rn "router\.back()" frontend-next/app frontend-next/components --include="*.tsx" | grep -v "back-button.tsx"

Fix: Replace with <BackButton fallbackHref="/parent-route" />

3. Custom Spinner Patterns (Should use Spinner)

echo "=== CUSTOM SPINNER PATTERNS ==="
grep -rn "animate-spin" frontend-next/app frontend-next/components --include="*.tsx" | grep -v "spinner.tsx" | head -20

Fix: Replace with <Spinner /> component

4. Fullscreen Pattern Duplication

echo "=== FULLSCREEN DUPLICATIONS ==="
grep -rn "Fullscreen\|setFullscreen\|isFullscreen" frontend-next/app frontend-next/components --include="*.tsx" | grep -v "component-registry"

SSoT: TeeemTableView has enableFullscreen prop for tables

5. Escape Key Handler Duplication

echo "=== ESCAPE HANDLER DUPLICATIONS ==="
grep -rn "Escape.*=>\|key.*Escape" frontend-next/app frontend-next/components --include="*.tsx" | head -20

Check: Should escape handling be in a shared component?

6. Unregistered Components

echo "=== UNREGISTERED COMPONENTS ==="
for file in frontend-next/components/ui/*.tsx; do
  component=$(basename "$file" .tsx)
  if ! grep -q "\"$component\"" frontend-next/lib/component-registry.ts 2>/dev/null; then
    count=$(grep -r "from.*ui/$component" frontend-next --include="*.tsx" 2>/dev/null | wc -l)
    if [ "$count" -gt 0 ]; then
      echo "NOT REGISTERED: $component (used $count times)"
    fi
  fi
done

Full Audit Command

Run this to check all SSoT violations at once:

echo "╔══════════════════════════════════════════════════════════════════╗"
echo "║           SSoT COMPONENT AUDITOR                                 ║"
echo "╚══════════════════════════════════════════════════════════════════╝"

echo ""
echo "=== 1. LUCIDE LOADER VIOLATIONS (use Spinner) ==="
grep -rn "Loader.*from.*lucide-react\|from.*lucide-react.*Loader" frontend-next/app frontend-next/components --include="*.tsx" 2>/dev/null | grep -v "spinner.tsx" || echo "None found"

echo ""
echo "=== 2. ROUTER.BACK() VIOLATIONS (use BackButton) ==="
grep -rn "router\.back()" frontend-next/app frontend-next/components --include="*.tsx" 2>/dev/null | grep -v "back-button.tsx" || echo "None found"

echo ""
echo "=== 3. CUSTOM ANIMATE-SPIN (use Spinner) ==="
grep -rn "animate-spin" frontend-next/app frontend-next/components --include="*.tsx" 2>/dev/null | grep -v "spinner.tsx" | head -10 || echo "None found"

echo ""
echo "=== 4. DEPRECATED IMPORTS ==="
grep -rn "from.*@/components/ui/combobox['\"]" frontend-next --include="*.tsx" 2>/dev/null | grep -v "combobox-dropdown" | head -5
grep -rn "from.*@/components/ui/loader" frontend-next --include="*.tsx" 2>/dev/null | head -5
grep -rn "from.*@/components/ui/drawer" frontend-next --include="*.tsx" 2>/dev/null | head -5
echo "(empty = good)"

echo ""
echo "╔══════════════════════════════════════════════════════════════════╗"
echo "║           AUDIT COMPLETE                                         ║"
echo "╚══════════════════════════════════════════════════════════════════╝"

Backend Data Model SSoT Checks

The root_path problem: Same concept stored in 3 tables. Catch this BEFORE it happens.

Run Before Adding ANY Database Column

# 1. Does this column already exist?
grep -n "COLUMN_NAME" backend/db/schema.rb

# 2. Is there a similar column?
grep -n "path\|config\|setting" backend/db/schema.rb | grep -i "RELATED_TERM"

Decision Tree:

  • Column exists? → SSoT VIOLATION - use existing column
  • Config/path data? → Goes in StorageConfiguration
  • Credential/auth data? → Goes in appropriate credential table
  • Setting data? → Goes in CompanySetting or CorporateCompanySetting

Full Backend SSoT Audit

echo "╔══════════════════════════════════════════════════════════════════╗"
echo "║           BACKEND SSoT AUDITOR                                   ║"
echo "╚══════════════════════════════════════════════════════════════════╝"

echo ""
echo "=== 1. DUPLICATE COLUMN NAMES ACROSS TABLES ==="
for col in root_path site_id drive_id client_id tenant_id endpoint bucket; do
  count=$(grep -c "\"$col\"" backend/db/schema.rb 2>/dev/null || echo 0)
  if [ "$count" -gt 1 ]; then
    echo "⚠️  WARNING: $col appears $count times:"
    grep -n "\"$col\"" backend/db/schema.rb
  fi
done
echo "(empty = good)"

echo ""
echo "=== 2. CONFIG-LIKE COLUMNS IN WRONG TABLES ==="
grep -n "root_path\|site_id\|drive_id" backend/db/schema.rb 2>/dev/null | \
  grep -v "storage_configurations" || echo "None found (good)"

echo ""
echo "=== 3. LEGACY PROVIDER-SPECIFIC COLUMNS ==="
grep -n "sharepoint_\|onedrive_\|outlook_" backend/db/schema.rb 2>/dev/null || echo "None found (good)"

echo ""
echo "=== 4. PATH COLUMNS OUTSIDE StorageConfiguration ==="
grep -n "_path\"" backend/db/schema.rb 2>/dev/null | \
  grep -v "storage_configurations\|file_path\|image_path\|avatar_path" || echo "None found (good)"

echo ""
echo "╔══════════════════════════════════════════════════════════════════╗"
echo "║           BACKEND AUDIT COMPLETE                                 ║"
echo "╚══════════════════════════════════════════════════════════════════╝"

Common SSoT Violations to Detect

PatternSSoT LocationRed Flag If Found In
root_pathStorageConfigurationAny credential or settings table
site_id, drive_idStorageConfiguration.connection_configMicrosoftCredential
client_id, tenant_idMicrosoftCredentialStorageConfiguration
*_path columnsStorageConfiguration.pathsCorporateCompanySetting
bucket, endpointS3CompatibleCredentialStorageConfiguration

Example Backend SSoT Violation Report

SSoT VIOLATION FOUND

I found `root_path` in 3 different tables:

1. backend/db/schema.rb:156 - s3_compatible_credentials
   t.string "root_path", default: ""

2. backend/db/schema.rb:234 - corporate_company_settings
   t.string "storage_root_path"  (legacy)

3. backend/db/schema.rb:412 - storage_configurations
   t.string "root_path"  ← THIS IS THE SSoT

RECOMMENDATION:
- StorageConfiguration.root_path is THE ONE
- Remove duplicate columns via migration
- Update code to read from StorageConfiguration only

Want me to consolidate?

Red Flags to Watch For

Constants & Logic

  • Same constant defined in multiple files
  • Same validation logic in frontend AND backend (pick one)
  • Config in both .env and config/*.yml
  • Two services doing the same transformation
  • Duplicate route definitions
  • Same helper method in multiple places

UI Patterns (NEW)

  • Fullscreen toggle implemented outside TeeemTableView
  • Loading spinners using Lucide icons instead of Spinner
  • Back navigation using router.back() instead of BackButton
  • Custom escape key handlers (should be in component)
  • Modal patterns not using Dialog/Sheet
  • Table implementations not using TeeemTableView

Example SSoT Violation Report

SSoT VIOLATION FOUND

I found fullscreen toggle implemented in 3 places:

1. frontend-next/app/(app)/admin/system/components/ScheduleMasterTab.tsx:328
   const [dataViewFullscreen, setDataViewFullscreen] = useState(false);

2. frontend-next/components/corporate/CorporateStructureTab.tsx:156
   const [isFullscreen, setIsFullscreen] = useState(false);

3. TeeemTableView.tsx - HAS enableFullscreen PROP (THE SSOT)

RECOMMENDATION:
- Use TeeemTableView's enableFullscreen prop
- Remove duplicate implementations
- Tables should not implement their own fullscreen

Want me to consolidate?

Common SSoT Locations in TEEEM

Frontend

ThingSSoT Location
Column typesTEEEM_DOCS/GOLD_STANDARD_TABLE.md
UI componentsfrontend-next/lib/component-registry.ts
Validation rulesBackend models
TimezoneCompanySetting
Loading indicatorSpinner from @/components/ui/spinner
Back navigationBackButton from @/components/ui/back-button
Searchable selectComboboxDropdown from @/components/ui/combobox-dropdown
Data tablesTeeemTableView from @/components/table/TeeemTableView
Side panelsSheet from @/components/ui/sheet
ModalsDialog from @/components/ui/dialog
Table fullscreenTeeemTableView with enableFullscreen prop

Backend (Data Model)

ThingSSoT Location❌ NOT Here
Provider typeStorageConfiguration.provider_typeHardcoded or guessed
Storage pathsStorageConfiguration.pathsCorporateCompanySetting (legacy)
Root pathStorageConfiguration.root_pathAny credential table
Connection configStorageConfiguration.connection_configSpread across credentials
Auth tokensProvider-specific credential modelStorageConfiguration
Company settingsCompanySettingCorporateCompanySetting (legacy)