Architecture Review Analyze, audit, and improve project structure. Key Principles - Measure before changing — Map structure and identify concrete issues before proposing changes - Clear boundaries — Layers (UI, logic, data) separated with consistent dependency direction - Colocation — Related code together; easy to find, change, and delete features - Incremental migration — Refactor in phases, validate each step with tests Quick Assessment - No circular dependencies - Consistent directory naming and grouping (by feature or by type) - Single responsibility per file/module, reasonable file size…

},\n to: {},\n },\n {\n name: 'no-ui-to-data',\n severity: 'error',\n from: { path: '^src/components' },\n to: { path: '^src/repositories' },\n },\n ],\n options: {\n doNotFollow: { path: 'node_modules' },\n tsConfig: { fileName: 'tsconfig.json' },\n },\n};\n```\n\n```bash\n# Run dependency-cruiser\nnpx depcruise src --config .dependency-cruiser.js\nnpx depcruise src --output-type dot | dot -T svg > deps.svg\n```\n\n### Knip Config (Find Unused)\n\n```json\n// knip.json\n{\n \"entry\": [\"src/index.ts\", \"src/main.ts\"],\n \"project\": [\"src/**/*.ts\"],\n \"ignore\": [\"**/*.test.ts\", \"**/*.spec.ts\"],\n \"ignoreDependencies\": [\"@types/*\"]\n}\n```\n\n```bash\nnpx knip # Find unused files, exports, dependencies\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":17003,"content_sha256":"31237a478ee89c5a23e271eceb1acb6416c9c24da728210a8b8366bb277d78f3"},{"filename":"references/anti-rationalization.md","content":"# Anti-Rationalization: Architecture Discipline\n\n## Iron Law\n\n**NO ARCHITECTURAL CHANGE WITHOUT DOCUMENTING THE TRADE-OFF.**\n\nEvery structural decision has costs. Name them. If you can't name the trade-off, you don't understand the change.\n\n---\n\n## Why This Works\n\nAuthority + commitment language doubles LLM compliance on discipline tasks (33% to 72%). Pre-rebutting common excuses prevents rationalization before it starts.\n\n---\n\n## Common Rationalizations\n\n| Rationalization | Reality |\n|----------------|---------|\n| \"It's just a small refactor\" | Small refactors compound. Three small refactors become a large undocumented architectural shift. Document why. |\n| \"We can fix it later\" | Later never comes. Fix it now or accept the trade-off explicitly with a documented decision. |\n| \"Everyone does it this way\" | Convention is not architecture. Justify from YOUR project's constraints and principles, not industry trends. |\n| \"This pattern is cleaner\" | \"Clean\" is subjective. State the measurable benefit: fewer dependencies, simpler testing, clearer boundaries. |\n| \"Let me just restructure this quickly\" | Restructuring is never quick. Map dependencies first. Identify what breaks. Plan the migration. |\n| \"The current architecture doesn't support this\" | Verify. Read the code. Most \"architecture won't support it\" claims come from not understanding the existing design. |\n| \"We need a new abstraction here\" | Do you? Three similar code blocks is better than a premature abstraction. Wait for the third use case. |\n| \"This is just technical debt cleanup\" | Technical debt has interest rates. Quantify the cost of keeping it vs. the cost of changing it. Then decide. |\n| \"The dependency is fine, it's well-maintained\" | Every dependency is a coupling point. Evaluate: API surface used, upgrade burden, fallback plan if abandoned. |\n| \"This won't affect other modules\" | Prove it. Check imports, shared types, common utilities. Architectural changes propagate further than you think. |\n| \"We need to future-proof this\" | You don't know the future. Design for today's requirements with clean interfaces. Extensibility is not speculation. |\n| \"Let me introduce a new pattern\" | One pattern per problem. Adding a new pattern without retiring the old one creates two ways to do things. |\n\n---\n\n## Red Flags — STOP\n\nWhen you detect ANY of these in your reasoning, STOP IMMEDIATELY.\n\n### Reasoning Phrases That Must Halt\n\n1. **\"Quick hack\"** — STOP. Hacks without follow-up tasks become permanent. Create the follow-up task or do it right.\n2. **\"Temporary workaround\"** — STOP. Is there a task to remove it? No? Then it's permanent. Treat it as such.\n3. **\"We'll migrate later\"** — STOP. Write the migration plan NOW or accept the current design.\n4. **\"This new pattern is better\"** — STOP. Better how? For whom? Document the trade-off or keep the existing pattern.\n5. **\"It's too coupled, let me decouple it\"** — STOP. Coupling is not inherently bad. Is this coupling causing actual problems? Name them.\n6. **\"Let me add a layer of indirection\"** — STOP. Every layer adds complexity. What specific problem does this layer solve?\n7. **\"The architecture is wrong\"** — STOP. Architecture is not right or wrong. It serves requirements. Have the requirements changed?\n8. **\"This needs a rewrite\"** — STOP. Rewrites are almost never justified. Identify the specific pain points and address them incrementally.\n\n### Structural Red Flags in Code\n\n1. **New directory created without documenting its purpose** — STOP. Every directory is a boundary decision.\n2. **Circular dependency introduced** — STOP. Extract the shared concern or restructure.\n3. **God module growing (>500 lines)** — STOP. Split by responsibility before adding more.\n4. **New abstraction with only one implementation** — STOP. Wait for the second use case.\n5. **Import from a deeper layer** — STOP. Dependencies flow downward. Inversion = architecture violation.\n\n### What To Do When You STOP\n\n1. State the architectural change you're about to make\n2. Document the trade-off: what you gain, what you lose\n3. Verify the change doesn't introduce circular dependencies\n4. Check if existing patterns already solve the problem\n5. If it's genuinely needed, add it to the task description as a deliberate decision\n\n---\n\n## Verification Checklist\n\nBefore reporting an architecture-related task as complete, verify ALL of these:\n\n- [ ] Every new directory/module has a documented purpose\n- [ ] No circular dependencies introduced (check imports)\n- [ ] No new abstractions with only one implementation\n- [ ] Dependency direction is consistent (higher layers depend on lower, never reverse)\n- [ ] No \"temporary\" code without a follow-up task to remove it\n- [ ] Trade-offs documented for any structural decision\n- [ ] File sizes remain under 500 lines\n- [ ] Existing patterns reused where applicable (no parallel patterns for same problem)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":4919,"content_sha256":"bd43cbc8ffc42bbcd8ac5dd4a36a691044f73aab499a85d5db4f487b82294f42"},{"filename":"references/cleanup-strategies.md","content":"# Cleanup Strategies\n\nDead code removal, consolidation, and naming conventions.\n\n## Dead Code Detection\n\n### Find Unused Exports\n\n```bash\n# Using ts-prune\nnpx ts-prune\n\n# Using knip (recommended)\nnpx knip\n\n# Using eslint-plugin-unused-imports\n# Add to .eslintrc.js\n```\n\n### Knip Configuration\n\n```json\n// knip.json\n{\n \"entry\": [\n \"src/index.ts\",\n \"src/app/**/*.tsx\",\n \"src/pages/**/*.tsx\"\n ],\n \"project\": [\"src/**/*.{ts,tsx}\"],\n \"ignore\": [\n \"**/*.test.ts\",\n \"**/*.spec.ts\",\n \"**/__mocks__/**\"\n ],\n \"ignoreDependencies\": [\n \"@types/*\",\n \"prettier\",\n \"eslint-*\"\n ],\n \"ignoreExportsUsedInFile\": true\n}\n```\n\n```bash\n# Run knip\nnpx knip # Report only\nnpx knip --fix # Auto-remove unused exports\nnpx knip --include files # Only unused files\nnpx knip --include exports # Only unused exports\n```\n\n### Find Unused Files\n\n```typescript\n// scripts/find-unused-files.ts\nimport fs from 'fs';\nimport path from 'path';\nimport madge from 'madge';\n\nasync function findUnusedFiles() {\n const result = await madge('src/index.ts', {\n fileExtensions: ['ts', 'tsx'],\n });\n \n const usedFiles = new Set(Object.keys(result.obj()));\n \n // Add files that are imported\n Object.values(result.obj()).forEach(imports => {\n imports.forEach(imp => usedFiles.add(imp));\n });\n \n // Get all files\n const allFiles: string[] = [];\n function walk(dir: string) {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.name === 'node_modules' || entry.name.startsWith('.')) continue;\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n walk(fullPath);\n } else if (/\\.(ts|tsx)$/.test(entry.name) && !entry.name.includes('.test.')) {\n allFiles.push(fullPath);\n }\n }\n }\n walk('src');\n \n // Find unused\n const unused = allFiles.filter(file => {\n const relative = path.relative('src', file);\n return !usedFiles.has(relative);\n });\n \n console.log('Potentially unused files:');\n unused.forEach(f => console.log(` ${f}`));\n}\n\nfindUnusedFiles();\n```\n\n### Find Unused Dependencies\n\n```bash\n# Using depcheck\nnpx depcheck\n\n# Using knip\nnpx knip --include dependencies\n\n# Using npm-check\nnpx npm-check\n```\n\n---\n\n## Code Consolidation\n\n### Consolidate Duplicate Functions\n\n```typescript\n// Step 1: Find duplicates\ngrep -r \"function formatDate\" src/\ngrep -r \"const formatDate\" src/\n\n// Step 2: Compare implementations\n// If identical or nearly identical, consolidate\n\n// Step 3: Create canonical version\n// src/shared/utils/date.ts\nexport function formatDate(date: Date, format: string = 'short'): string {\n // Best implementation\n}\n\n// Step 4: Update all usages\n// Use IDE's \"Find and Replace in Files\"\n\n// Step 5: Delete duplicates\n```\n\n### Consolidate Similar Components\n\n```typescript\n// BEFORE: Multiple similar buttons\n// PrimaryButton.tsx\nexport function PrimaryButton({ children, onClick }) {\n return \u003cbutton className=\"bg-blue-500\" onClick={onClick}>{children}\u003c/button>;\n}\n\n// SecondaryButton.tsx\nexport function SecondaryButton({ children, onClick }) {\n return \u003cbutton className=\"bg-gray-500\" onClick={onClick}>{children}\u003c/button>;\n}\n\n// DangerButton.tsx\nexport function DangerButton({ children, onClick }) {\n return \u003cbutton className=\"bg-red-500\" onClick={onClick}>{children}\u003c/button>;\n}\n\n// AFTER: Single configurable component\n// Button.tsx\ntype ButtonVariant = 'primary' | 'secondary' | 'danger';\n\nconst variantStyles: Record\u003cButtonVariant, string> = {\n primary: 'bg-blue-500 text-white',\n secondary: 'bg-gray-500 text-white',\n danger: 'bg-red-500 text-white',\n};\n\ninterface ButtonProps {\n variant?: ButtonVariant;\n children: React.ReactNode;\n onClick?: () => void;\n}\n\nexport function Button({ variant = 'primary', children, onClick }: ButtonProps) {\n return (\n \u003cbutton className={variantStyles[variant]} onClick={onClick}>\n {children}\n \u003c/button>\n );\n}\n\n// Usage\n\u003cButton variant=\"primary\">Submit\u003c/Button>\n\u003cButton variant=\"danger\">Delete\u003c/Button>\n```\n\n### Consolidate Configuration\n\n```typescript\n// BEFORE: Config scattered\n// src/services/api.ts\nconst API_URL = process.env.NEXT_PUBLIC_API_URL;\n\n// src/lib/auth.ts\nconst AUTH_SECRET = process.env.AUTH_SECRET;\n\n// src/utils/logger.ts\nconst LOG_LEVEL = process.env.LOG_LEVEL || 'info';\n\n// AFTER: Centralized config\n// src/config/index.ts\nimport { z } from 'zod';\n\nconst envSchema = z.object({\n NODE_ENV: z.enum(['development', 'production', 'test']),\n API_URL: z.string().url(),\n AUTH_SECRET: z.string().min(32),\n LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),\n DATABASE_URL: z.string(),\n});\n\nconst parsed = envSchema.safeParse(process.env);\n\nif (!parsed.success) {\n console.error('❌ Invalid environment variables:', parsed.error.format());\n process.exit(1);\n}\n\nexport const config = parsed.data;\n\n// Usage everywhere\nimport { config } from '@/config';\nconst apiUrl = config.API_URL;\n```\n\n---\n\n## Naming Conventions\n\n### File Naming\n\n```\n✅ Recommended patterns:\n\nComponents: PascalCase.tsx UserList.tsx, OrderForm.tsx\nHooks: camelCase.ts useUser.ts, useOrders.ts\nUtils: camelCase.ts formatDate.ts, validation.ts\nTypes: camelCase.ts user.types.ts (or types.ts)\nConstants: camelCase.ts constants.ts\nServices: camelCase.ts user.service.ts\nTests: *.test.ts user.service.test.ts\nStyles: *.module.css Button.module.css\n\n❌ Avoid:\n- Mixed conventions in same project\n- Generic names: utils.ts, helpers.ts, misc.ts\n- Abbreviations: usr.ts, ord.ts\n```\n\n### Directory Naming\n\n```\n✅ Recommended:\n- Lowercase with hyphens: user-management/\n- Or lowercase: users/, orders/\n- Consistent across project\n\n❌ Avoid:\n- PascalCase folders: UserManagement/\n- Mixed conventions\n- Deep nesting\n```\n\n### Rename Script\n\n```typescript\n// scripts/rename-files.ts\nimport fs from 'fs';\nimport path from 'path';\n\nconst renamePatterns: Array\u003c{\n match: RegExp;\n transform: (name: string) => string;\n}> = [\n // userService.ts → user.service.ts\n {\n match: /^([a-z]+)Service\\.ts$/,\n transform: (name) => name.replace(/^([a-z]+)Service\\.ts$/, '$1.service.ts'),\n },\n // UserComponent.tsx → User.tsx (if in components folder)\n {\n match: /^([A-Z][a-zA-Z]+)Component\\.tsx$/,\n transform: (name) => name.replace(/Component\\.tsx$/, '.tsx'),\n },\n];\n\nfunction renameFiles(dir: string, dryRun = true) {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n \n for (const entry of entries) {\n if (entry.name === 'node_modules' || entry.name.startsWith('.')) continue;\n \n const fullPath = path.join(dir, entry.name);\n \n if (entry.isDirectory()) {\n renameFiles(fullPath, dryRun);\n } else {\n for (const pattern of renamePatterns) {\n if (pattern.match.test(entry.name)) {\n const newName = pattern.transform(entry.name);\n const newPath = path.join(dir, newName);\n \n if (dryRun) {\n console.log(`Would rename: ${fullPath} → ${newPath}`);\n } else {\n fs.renameSync(fullPath, newPath);\n console.log(`Renamed: ${fullPath} → ${newPath}`);\n }\n break;\n }\n }\n }\n }\n}\n\n// Dry run first\nrenameFiles('src', true);\n\n// Then actual rename\n// renameFiles('src', false);\n```\n\n---\n\n## Import Cleanup\n\n### Remove Unused Imports\n\n```bash\n# Using eslint\nnpx eslint --fix src/\n\n# Using organize-imports-cli\nnpx organize-imports-cli src/**/*.ts\n\n# Using prettier-plugin-organize-imports\n# Add to prettier config\n```\n\n### ESLint Configuration\n\n```javascript\n// .eslintrc.js\nmodule.exports = {\n plugins: ['unused-imports', 'import'],\n rules: {\n 'unused-imports/no-unused-imports': 'error',\n 'unused-imports/no-unused-vars': [\n 'warn',\n {\n vars: 'all',\n varsIgnorePattern: '^_',\n args: 'after-used',\n argsIgnorePattern: '^_',\n },\n ],\n 'import/no-duplicates': 'error',\n },\n};\n```\n\n### Sort and Organize Imports\n\n```javascript\n// .prettierrc\n{\n \"plugins\": [\"@trivago/prettier-plugin-sort-imports\"],\n \"importOrder\": [\n \"^react\",\n \"^next\",\n \"\u003cTHIRD_PARTY_MODULES>\",\n \"^@/(.*)$\",\n \"^[./]\"\n ],\n \"importOrderSeparation\": true,\n \"importOrderSortSpecifiers\": true\n}\n```\n\n---\n\n## File Structure Cleanup\n\n### Flatten Deep Nesting\n\n```typescript\n// BEFORE: Too deep\nsrc/features/users/components/forms/inputs/text/TextInput.tsx\n\n// AFTER: Flattened\nsrc/features/users/components/TextInput.tsx\n\n// Or if shared:\nsrc/shared/components/inputs/TextInput.tsx\n```\n\n### Remove Empty Directories\n\n```bash\n# Find empty directories\nfind src -type d -empty\n\n# Remove empty directories\nfind src -type d -empty -delete\n```\n\n### Consolidate Small Files\n\n```typescript\n// BEFORE: Many tiny files\n// src/utils/isEmail.ts (3 lines)\n// src/utils/isPhone.ts (3 lines)\n// src/utils/isUrl.ts (3 lines)\n\n// AFTER: Single file\n// src/utils/validation.ts\nexport function isEmail(value: string): boolean { /* ... */ }\nexport function isPhone(value: string): boolean { /* ... */ }\nexport function isUrl(value: string): boolean { /* ... */ }\n```\n\n---\n\n## Type Cleanup\n\n### Remove Duplicate Types\n\n```typescript\n// Step 1: Find similar types\ngrep -r \"interface User\" src/\ngrep -r \"type User\" src/\n\n// Step 2: Compare and merge\n// BEFORE:\n// types/user.ts\ninterface User { id: string; name: string; email: string; }\n\n// services/types.ts\ninterface UserData { id: string; name: string; email: string; } // Duplicate!\n\n// AFTER:\n// types/user.ts\nexport interface User {\n id: string;\n name: string;\n email: string;\n}\n\n// Use everywhere\nimport { User } from '@/types/user';\n```\n\n### Remove `any` Types\n\n```typescript\n// Find all 'any' usages\ngrep -r \": any\" src/ | grep -v node_modules\n\n// Replace with proper types\n// BEFORE\nfunction processData(data: any): any {\n return data.map((item: any) => item.value);\n}\n\n// AFTER\ninterface DataItem {\n value: string;\n // ... other properties\n}\n\nfunction processData(data: DataItem[]): string[] {\n return data.map(item => item.value);\n}\n```\n\n### Type Consolidation Script\n\n```typescript\n// scripts/find-duplicate-types.ts\nimport fs from 'fs';\nimport path from 'path';\n\ninterface TypeDefinition {\n name: string;\n file: string;\n line: number;\n type: 'interface' | 'type';\n}\n\nfunction findTypes(dir: string): TypeDefinition[] {\n const types: TypeDefinition[] = [];\n \n function walk(currentDir: string) {\n const entries = fs.readdirSync(currentDir, { withFileTypes: true });\n \n for (const entry of entries) {\n if (entry.name === 'node_modules') continue;\n \n const fullPath = path.join(currentDir, entry.name);\n \n if (entry.isDirectory()) {\n walk(fullPath);\n } else if (/\\.(ts|tsx)$/.test(entry.name)) {\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lines = content.split('\\n');\n \n lines.forEach((line, index) => {\n // Match interface declarations\n const interfaceMatch = line.match(/^export\\s+interface\\s+(\\w+)/);\n if (interfaceMatch) {\n types.push({\n name: interfaceMatch[1],\n file: fullPath,\n line: index + 1,\n type: 'interface',\n });\n }\n \n // Match type declarations\n const typeMatch = line.match(/^export\\s+type\\s+(\\w+)/);\n if (typeMatch) {\n types.push({\n name: typeMatch[1],\n file: fullPath,\n line: index + 1,\n type: 'type',\n });\n }\n });\n }\n }\n }\n \n walk(dir);\n return types;\n}\n\n// Find duplicates\nconst types = findTypes('src');\nconst byName = new Map\u003cstring, TypeDefinition[]>();\n\ntypes.forEach(t => {\n const existing = byName.get(t.name) || [];\n existing.push(t);\n byName.set(t.name, existing);\n});\n\nconsole.log('Duplicate type definitions:');\nbyName.forEach((definitions, name) => {\n if (definitions.length > 1) {\n console.log(`\\n${name}:`);\n definitions.forEach(d => {\n console.log(` ${d.file}:${d.line}`);\n });\n }\n});\n```\n\n---\n\n## Comment Cleanup\n\n### Remove TODO/FIXME Accumulation\n\n```bash\n# Find all TODOs\ngrep -rn \"TODO\\|FIXME\\|HACK\\|XXX\" src/\n\n# Count by type\ngrep -r \"TODO\" src/ | wc -l\ngrep -r \"FIXME\" src/ | wc -l\n```\n\n### Process TODO Comments\n\n```typescript\n// scripts/process-todos.ts\nimport fs from 'fs';\nimport path from 'path';\n\ninterface TodoItem {\n file: string;\n line: number;\n type: 'TODO' | 'FIXME' | 'HACK' | 'XXX';\n text: string;\n author?: string;\n date?: string;\n}\n\nfunction extractTodos(dir: string): TodoItem[] {\n const todos: TodoItem[] = [];\n const todoRegex = /\\/\\/\\s*(TODO|FIXME|HACK|XXX)(\\([^)]+\\))?:?\\s*(.+)/i;\n \n function walk(currentDir: string) {\n const entries = fs.readdirSync(currentDir, { withFileTypes: true });\n \n for (const entry of entries) {\n if (entry.name === 'node_modules') continue;\n \n const fullPath = path.join(currentDir, entry.name);\n \n if (entry.isDirectory()) {\n walk(fullPath);\n } else if (/\\.(ts|tsx|js|jsx)$/.test(entry.name)) {\n const content = fs.readFileSync(fullPath, 'utf-8');\n const lines = content.split('\\n');\n \n lines.forEach((line, index) => {\n const match = line.match(todoRegex);\n if (match) {\n todos.push({\n file: path.relative(process.cwd(), fullPath),\n line: index + 1,\n type: match[1].toUpperCase() as TodoItem['type'],\n text: match[3].trim(),\n author: match[2]?.replace(/[()]/g, ''),\n });\n }\n });\n }\n }\n }\n \n walk(dir);\n return todos;\n}\n\nconst todos = extractTodos('src');\n\n// Group by type\nconst byType = {\n FIXME: todos.filter(t => t.type === 'FIXME'),\n TODO: todos.filter(t => t.type === 'TODO'),\n HACK: todos.filter(t => t.type === 'HACK'),\n XXX: todos.filter(t => t.type === 'XXX'),\n};\n\n// Report\nconsole.log('=== TODO/FIXME Report ===\\n');\n\nif (byType.FIXME.length > 0) {\n console.log(`🔴 FIXME (${byType.FIXME.length}):`);\n byType.FIXME.forEach(t => {\n console.log(` ${t.file}:${t.line} - ${t.text}`);\n });\n}\n\nif (byType.TODO.length > 0) {\n console.log(`\\n🟡 TODO (${byType.TODO.length}):`);\n byType.TODO.slice(0, 20).forEach(t => {\n console.log(` ${t.file}:${t.line} - ${t.text}`);\n });\n if (byType.TODO.length > 20) {\n console.log(` ... and ${byType.TODO.length - 20} more`);\n }\n}\n```\n\n---\n\n## Cleanup Checklist\n\n### Quick Wins (\u003c 1 hour)\n- [ ] Remove unused imports (`eslint --fix`)\n- [ ] Sort imports consistently\n- [ ] Remove console.log statements\n- [ ] Fix obvious type errors\n\n### Short-term (1 day)\n- [ ] Run knip, address unused exports\n- [ ] Consolidate duplicate utility functions\n- [ ] Standardize file naming\n- [ ] Remove empty files and directories\n\n### Medium-term (1 week)\n- [ ] Consolidate similar components\n- [ ] Centralize configuration\n- [ ] Address TODO/FIXME backlog\n- [ ] Update outdated dependencies\n\n### Long-term (ongoing)\n- [ ] Enforce conventions with linting\n- [ ] Regular dependency audits\n- [ ] Periodic architecture reviews\n- [ ] Documentation updates\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":15288,"content_sha256":"f1439129a44dedfa6760af75532f11903ea496c0c9357407f4f064346f919ef2"},{"filename":"references/dependency-management.md","content":"# Dependency Management\n\nManaging module boundaries, circular dependencies, and coupling.\n\n## Dependency Direction\n\n### The Dependency Rule\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│ DEPENDENCY DIRECTION │\n├─────────────────────────────────────────────────────────────┤\n│ │\n│ UI Layer → Allowed to import from │\n│ (Components) Services, Utils, Types │\n│ │ │\n│ ▼ │\n│ Application Layer → Allowed to import from │\n│ (Services, Hooks) Repositories, Utils, Types │\n│ │ │\n│ ▼ │\n│ Data Layer → Allowed to import from │\n│ (Repositories) Models, Utils, Types │\n│ │ │\n│ ▼ │\n│ Core Layer → No external imports │\n│ (Models, Types) (self-contained) │\n│ │\n│ Utils/Shared → Can be imported by any layer │\n│ Must not import from layers │\n│ │\n└─────────────────────────────────────────────────────────────┘\n```\n\n### Enforce with ESLint\n\n```javascript\n// .eslintrc.js\nmodule.exports = {\n plugins: ['import'],\n rules: {\n 'import/no-restricted-paths': [\n 'error',\n {\n zones: [\n // Repositories cannot import from services\n {\n target: './src/repositories',\n from: './src/services',\n message: 'Repositories cannot depend on services',\n },\n // Services cannot import from controllers\n {\n target: './src/services',\n from: './src/controllers',\n message: 'Services cannot depend on controllers',\n },\n // Components cannot import from repositories\n {\n target: './src/components',\n from: './src/repositories',\n message: 'Components must not access data layer directly',\n },\n // Shared/utils cannot import from features\n {\n target: './src/shared',\n from: './src/features',\n message: 'Shared code cannot depend on features',\n },\n ],\n },\n ],\n },\n};\n```\n\n---\n\n## Circular Dependencies\n\n### Detecting Circular Dependencies\n\n```bash\n# Using madge\nnpx madge --circular src/\n\n# Using dependency-cruiser\nnpx depcruise --validate .dependency-cruiser.js src/\n```\n\n### Common Circular Patterns\n\n#### Pattern 1: Service-to-Service\n\n```typescript\n// ❌ CIRCULAR\n// userService.ts\nimport { OrderService } from './orderService';\nexport class UserService {\n constructor(private orderService: OrderService) {}\n getUserOrders(userId: string) {\n return this.orderService.getOrdersByUser(userId);\n }\n}\n\n// orderService.ts\nimport { UserService } from './userService';\nexport class OrderService {\n constructor(private userService: UserService) {}\n getOrderWithUser(orderId: string) {\n const order = this.getOrder(orderId);\n return { ...order, user: this.userService.getUser(order.userId) };\n }\n}\n```\n\n**Fix 1: Extract Shared Logic**\n\n```typescript\n// orderUserService.ts (new)\nexport class OrderUserService {\n constructor(\n private userRepo: UserRepository,\n private orderRepo: OrderRepository,\n ) {}\n \n getUserOrders(userId: string) {\n return this.orderRepo.findByUser(userId);\n }\n \n getOrderWithUser(orderId: string) {\n const order = this.orderRepo.findById(orderId);\n const user = this.userRepo.findById(order.userId);\n return { ...order, user };\n }\n}\n```\n\n**Fix 2: Use Events**\n\n```typescript\n// userService.ts\nexport class UserService {\n async deleteUser(userId: string) {\n await this.userRepo.delete(userId);\n this.eventBus.emit('user.deleted', { userId });\n }\n}\n\n// orderService.ts\nexport class OrderService {\n constructor(private eventBus: EventBus) {\n this.eventBus.on('user.deleted', this.handleUserDeleted.bind(this));\n }\n \n private async handleUserDeleted({ userId }: { userId: string }) {\n await this.cancelUserOrders(userId);\n }\n}\n```\n\n**Fix 3: Dependency Injection with Interfaces**\n\n```typescript\n// interfaces/IOrderService.ts\nexport interface IOrderService {\n getOrdersByUser(userId: string): Promise\u003cOrder[]>;\n}\n\n// userService.ts\nimport { IOrderService } from '../interfaces/IOrderService';\n\nexport class UserService {\n private orderService?: IOrderService;\n \n setOrderService(orderService: IOrderService) {\n this.orderService = orderService;\n }\n \n getUserOrders(userId: string) {\n return this.orderService?.getOrdersByUser(userId);\n }\n}\n\n// Compose at application startup\nconst userService = new UserService();\nconst orderService = new OrderService();\nuserService.setOrderService(orderService);\n```\n\n#### Pattern 2: Type Imports Causing Cycles\n\n```typescript\n// ❌ types.ts imports from services for types\n// types.ts\nimport { UserService } from './services/userService';\nexport type UserServiceType = typeof UserService;\n\n// services/userService.ts\nimport { User } from '../types'; // Circular!\n```\n\n**Fix: Separate Type Files**\n\n```typescript\n// types/user.types.ts (no imports from services)\nexport interface User {\n id: string;\n email: string;\n}\n\n// services/userService.ts\nimport { User } from '../types/user.types'; // No cycle\n```\n\n#### Pattern 3: Index File Cycles\n\n```typescript\n// ❌ Barrel file creates cycle\n// features/index.ts\nexport * from './users';\nexport * from './orders';\n\n// features/users/index.ts\nexport * from './UserList';\n\n// features/users/UserList.tsx\nimport { OrderSummary } from '../orders'; // Goes through barrel → cycle!\n```\n\n**Fix: Direct Imports**\n\n```typescript\n// features/users/UserList.tsx\nimport { OrderSummary } from '../orders/OrderSummary'; // Direct import\n```\n\n---\n\n## Coupling Reduction\n\n### Tight vs Loose Coupling\n\n```typescript\n// ❌ TIGHT COUPLING\n// Direct dependency on concrete class and its internals\nclass OrderService {\n async createOrder(data: CreateOrderDto) {\n const user = await prisma.user.findUnique({ where: { id: data.userId } });\n if (!user) throw new Error('User not found');\n \n const product = await prisma.product.findUnique({ where: { id: data.productId } });\n if (product.stock \u003c data.quantity) throw new Error('Insufficient stock');\n \n await prisma.product.update({\n where: { id: data.productId },\n data: { stock: product.stock - data.quantity },\n });\n \n const order = await prisma.order.create({ data });\n \n await sendEmail(user.email, 'Order Confirmation', orderTemplate(order));\n \n return order;\n }\n}\n\n// ✅ LOOSE COUPLING\n// Depends on interfaces, single responsibility\nclass OrderService {\n constructor(\n private userRepository: IUserRepository,\n private productRepository: IProductRepository,\n private orderRepository: IOrderRepository,\n private inventoryService: IInventoryService,\n private notificationService: INotificationService,\n ) {}\n \n async createOrder(data: CreateOrderDto) {\n const user = await this.userRepository.findById(data.userId);\n if (!user) throw new UserNotFoundError(data.userId);\n \n await this.inventoryService.reserveStock(data.productId, data.quantity);\n \n const order = await this.orderRepository.create(data);\n \n await this.notificationService.sendOrderConfirmation(user, order);\n \n return order;\n }\n}\n```\n\n### Dependency Injection\n\n```typescript\n// container.ts\nimport { Container } from 'inversify';\n\nconst container = new Container();\n\n// Bind interfaces to implementations\ncontainer.bind\u003cIUserRepository>('IUserRepository').to(UserRepository);\ncontainer.bind\u003cIOrderRepository>('IOrderRepository').to(OrderRepository);\ncontainer.bind\u003cIEmailService>('IEmailService').to(EmailService);\ncontainer.bind\u003cUserService>('UserService').to(UserService);\ncontainer.bind\u003cOrderService>('OrderService').to(OrderService);\n\nexport { container };\n\n// Usage\nconst orderService = container.get\u003cOrderService>('OrderService');\n```\n\n### Feature Isolation\n\n```typescript\n// ❌ Features tightly coupled\n// features/orders/OrderForm.tsx\nimport { useUser } from '../users/hooks/useUser';\nimport { UserAvatar } from '../users/components/UserAvatar';\nimport { ProductCard } from '../products/components/ProductCard';\nimport { useProducts } from '../products/hooks/useProducts';\nimport { calculateShipping } from '../shipping/utils';\n\n// ✅ Features loosely coupled via shared interfaces\n\n// shared/types/index.ts\nexport interface UserInfo {\n id: string;\n name: string;\n avatar: string;\n}\n\n// features/orders/OrderForm.tsx\nimport { UserInfo } from '@/shared/types';\n\ninterface OrderFormProps {\n user: UserInfo; // Receives data, doesn't fetch\n products: Product[];\n onSubmit: (order: OrderData) => void;\n}\n\n// Parent component composes features\n// pages/checkout.tsx\nimport { useUser } from '@/features/users';\nimport { useProducts } from '@/features/products';\nimport { OrderForm } from '@/features/orders';\n\nfunction CheckoutPage() {\n const user = useUser();\n const products = useProducts();\n \n return \u003cOrderForm user={user} products={products} />;\n}\n```\n\n---\n\n## Module Boundaries\n\n### Public API Definition\n\n```typescript\n// features/users/index.ts\n// Only export what other features should use\n\n// ✅ Public API\nexport { UserList } from './components/UserList';\nexport { UserCard } from './components/UserCard';\nexport { useUser } from './hooks/useUser';\nexport { useUsers } from './hooks/useUsers';\nexport type { User, CreateUserDto } from './types';\n\n// ❌ Don't export internals\n// export { UserListItem } from './components/UserListItem'; // Internal\n// export { formatUserName } from './utils'; // Internal\n// export { userApi } from './api'; // Internal\n```\n\n### Enforce Boundaries with ESLint\n\n```javascript\n// .eslintrc.js\nmodule.exports = {\n rules: {\n 'no-restricted-imports': [\n 'error',\n {\n patterns: [\n {\n group: ['@/features/*/components/*'],\n message: 'Import from feature index instead: @/features/featureName',\n },\n {\n group: ['@/features/*/hooks/*'],\n message: 'Import from feature index instead',\n },\n {\n group: ['@/features/*/api*'],\n message: 'Feature APIs are internal, use exported hooks',\n },\n ],\n },\n ],\n },\n};\n```\n\n### Package-Based Boundaries (Monorepo)\n\n```json\n// packages/users/package.json\n{\n \"name\": \"@myorg/users\",\n \"main\": \"src/index.ts\",\n \"exports\": {\n \".\": \"./src/index.ts\",\n \"./components\": \"./src/components/index.ts\",\n \"./hooks\": \"./src/hooks/index.ts\"\n }\n}\n\n// Only what's in exports is accessible\n// import { UserList } from '@myorg/users/components'; // ✅ Allowed\n// import { UserListItem } from '@myorg/users/components/UserListItem'; // ❌ Not exported\n```\n\n---\n\n## Import Organization\n\n### Consistent Import Order\n\n```typescript\n// Recommended order:\n// 1. Node built-ins\n// 2. External packages\n// 3. Internal packages (monorepo)\n// 4. Absolute imports from src\n// 5. Relative imports\n\n// Example:\nimport path from 'path'; // 1. Node\nimport React, { useState } from 'react'; // 2. External\nimport { Button } from '@myorg/ui'; // 3. Internal package\nimport { useAuth } from '@/features/auth'; // 4. Absolute\nimport { formatDate } from '../../utils/date'; // 5. Relative\nimport { UserCard } from './UserCard'; // 5. Relative (same dir)\n```\n\n### ESLint Import Order\n\n```javascript\n// .eslintrc.js\nmodule.exports = {\n plugins: ['import'],\n rules: {\n 'import/order': [\n 'error',\n {\n groups: [\n 'builtin',\n 'external',\n 'internal',\n ['parent', 'sibling', 'index'],\n ],\n pathGroups: [\n { pattern: '@myorg/**', group: 'internal' },\n { pattern: '@/**', group: 'internal' },\n ],\n 'newlines-between': 'always',\n alphabetize: { order: 'asc' },\n },\n ],\n },\n};\n```\n\n---\n\n## Dependency Graphs\n\n### Visualizing Dependencies\n\n```bash\n# Generate SVG graph\nnpx madge --image deps.svg src/index.ts\n\n# Generate for specific directory\nnpx madge --image users-deps.svg src/features/users/\n\n# Show only circular\nnpx madge --circular --image circular.svg src/\n\n# JSON output for processing\nnpx madge --json src/ > deps.json\n```\n\n### Analyzing Graph\n\n```typescript\n// scripts/analyze-deps.ts\nimport madge from 'madge';\n\nasync function analyzeDependencies() {\n const result = await madge('src/index.ts', {\n fileExtensions: ['ts', 'tsx'],\n excludeRegExp: [/\\.test\\.ts$/, /\\.spec\\.ts$/],\n });\n \n // Circular dependencies\n const circular = result.circular();\n if (circular.length > 0) {\n console.log('⚠️ Circular dependencies found:');\n circular.forEach(cycle => {\n console.log(' ', cycle.join(' → '));\n });\n }\n \n // Orphans (not imported anywhere)\n const orphans = result.orphans();\n if (orphans.length > 0) {\n console.log('\\n📦 Orphan files (not imported):');\n orphans.forEach(file => console.log(' ', file));\n }\n \n // Most depended upon (potential god modules)\n const deps = result.obj();\n const dependedUpon = new Map\u003cstring, number>();\n \n Object.values(deps).forEach(imports => {\n imports.forEach(imp => {\n dependedUpon.set(imp, (dependedUpon.get(imp) || 0) + 1);\n });\n });\n \n const sorted = [...dependedUpon.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, 10);\n \n console.log('\\n🏆 Most imported files:');\n sorted.forEach(([file, count]) => {\n console.log(` ${count.toString().padStart(3)} imports: ${file}`);\n });\n}\n\nanalyzeDependencies();\n```\n\n---\n\n## Breaking Dependency Cycles\n\n### Step-by-Step Process\n\n```\n1. Identify the cycle\n madge --circular src/\n\n2. Understand WHY the cycle exists\n - Shared types?\n - Shared utilities?\n - Bidirectional relationship?\n\n3. Choose resolution strategy:\n - Extract shared code\n - Use dependency injection\n - Use events/callbacks\n - Restructure modules\n\n4. Implement fix in stages\n - Create new module/interface\n - Update one side of cycle\n - Run tests\n - Update other side\n - Run tests\n - Remove old imports\n\n5. Verify cycle is broken\n madge --circular src/\n```\n\n### Common Resolutions\n\n| Cycle Pattern | Resolution |\n|---------------|------------|\n| A → B → A (direct) | Extract common code to C, both import C |\n| A ↔ B (types only) | Move shared types to separate file |\n| A → B → C → A | Extract interface, use DI |\n| Service ↔ Service | Use events or mediator |\n| Feature ↔ Feature | Pass data via props/context |\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":15641,"content_sha256":"2b5b60b461aaf5d0e4f6ee62a5dd1d34f19c6e075817fd65a2ad0ab69a76c719"},{"filename":"references/refactoring-patterns.md","content":"# Refactoring Patterns\n\nSafe techniques for restructuring code and migrating architectures.\n\n## Core Principles\n\n### 1. Never Refactor Without Tests\n\n```typescript\n// Before any structural change:\n// 1. Ensure tests exist for affected code\n// 2. Run tests to verify they pass\n// 3. Make change\n// 4. Run tests again\n// 5. Commit\n\n// If no tests exist, add them first\ndescribe('UserService', () => {\n it('creates user with valid data', async () => {\n const user = await userService.create({ email: '[email protected]' });\n expect(user.id).toBeDefined();\n });\n \n // Add more tests to cover behavior before refactoring\n});\n```\n\n### 2. Small, Incremental Changes\n\n```\n❌ Bad: One massive commit that restructures everything\n✅ Good: Series of small commits, each passing tests\n\nCommit 1: Create new folder structure\nCommit 2: Move UserService to new location\nCommit 3: Update imports for UserService\nCommit 4: Move OrderService to new location\nCommit 5: Update imports for OrderService\n...\n```\n\n### 3. Parallel Structures (Strangler Fig)\n\n```typescript\n// Step 1: Create new structure alongside old\nsrc/\n├── services/ # Old location\n│ └── userService.ts\n└── modules/ # New location\n └── users/\n └── user.service.ts # Copy of userService\n\n// Step 2: New code uses new location\n// Step 3: Migrate old consumers one by one\n// Step 4: Delete old location when empty\n```\n\n---\n\n## File Movement Patterns\n\n### Safe File Move\n\n```bash\n# Step 1: Create new directory\nmkdir -p src/modules/users\n\n# Step 2: Copy file (don't move yet)\ncp src/services/userService.ts src/modules/users/user.service.ts\n\n# Step 3: Update the new file's imports\n# (Fix relative paths)\n\n# Step 4: Create re-export from old location\n# src/services/userService.ts\nexport * from '../modules/users/user.service';\n\n# Step 5: Run tests - everything should still work\n\n# Step 6: Update consumers to import from new location\n# (One file at a time, running tests between each)\n\n# Step 7: When no consumers use old location, delete it\n```\n\n### Bulk File Movement Script\n\n```typescript\n// scripts/move-module.ts\nimport fs from 'fs';\nimport path from 'path';\n\ninterface MoveConfig {\n from: string;\n to: string;\n updateImports: boolean;\n}\n\nasync function moveModule(config: MoveConfig): Promise\u003cvoid> {\n const { from, to, updateImports } = config;\n \n // 1. Create target directory\n fs.mkdirSync(path.dirname(to), { recursive: true });\n \n // 2. Copy file\n fs.copyFileSync(from, to);\n \n // 3. Create re-export at old location\n const relativePath = path.relative(path.dirname(from), to).replace(/\\.ts$/, '');\n fs.writeFileSync(from, `export * from '${relativePath}';\\n`);\n \n console.log(`Moved: ${from} → ${to}`);\n console.log(`Created re-export at: ${from}`);\n \n if (updateImports) {\n // 4. Find and update all imports\n await updateAllImports(from, to);\n }\n}\n\nasync function updateAllImports(oldPath: string, newPath: string): Promise\u003cvoid> {\n const srcDir = './src';\n const oldImportPath = oldPath.replace(/^\\.\\/src\\//, '').replace(/\\.ts$/, '');\n const newImportPath = newPath.replace(/^\\.\\/src\\//, '').replace(/\\.ts$/, '');\n \n function walkAndUpdate(dir: string) {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n \n for (const entry of entries) {\n if (entry.name === 'node_modules') continue;\n \n const fullPath = path.join(dir, entry.name);\n \n if (entry.isDirectory()) {\n walkAndUpdate(fullPath);\n } else if (/\\.(ts|tsx)$/.test(entry.name)) {\n let content = fs.readFileSync(fullPath, 'utf-8');\n const originalContent = content;\n \n // Update imports\n content = content.replace(\n new RegExp(`from ['\"]([./@]*)${oldImportPath}['\"]`, 'g'),\n `from '$1${newImportPath}'`\n );\n \n if (content !== originalContent) {\n fs.writeFileSync(fullPath, content);\n console.log(`Updated imports in: ${fullPath}`);\n }\n }\n }\n }\n \n walkAndUpdate(srcDir);\n}\n```\n\n---\n\n## Module Extraction Patterns\n\n### Extract to Separate Module\n\n```typescript\n// BEFORE: God file with mixed concerns\n// src/services/userService.ts (500+ lines)\n\nexport class UserService {\n async createUser() { /* ... */ }\n async updateUser() { /* ... */ }\n async deleteUser() { /* ... */ }\n async sendWelcomeEmail() { /* ... */ }\n async sendPasswordReset() { /* ... */ }\n async validateUserData() { /* ... */ }\n async checkPermissions() { /* ... */ }\n}\n\n// AFTER: Extracted into focused modules\n\n// src/modules/users/user.service.ts\nexport class UserService {\n constructor(\n private emailService: EmailService,\n private validationService: ValidationService,\n ) {}\n \n async createUser() { /* ... */ }\n async updateUser() { /* ... */ }\n async deleteUser() { /* ... */ }\n}\n\n// src/modules/email/email.service.ts\nexport class EmailService {\n async sendWelcomeEmail() { /* ... */ }\n async sendPasswordReset() { /* ... */ }\n}\n\n// src/modules/validation/validation.service.ts\nexport class ValidationService {\n async validateUserData() { /* ... */ }\n}\n```\n\n### Extract Shared Utilities\n\n```typescript\n// BEFORE: Utility functions scattered in multiple files\n\n// src/services/userService.ts\nfunction formatDate(date: Date): string { /* ... */ }\nfunction generateId(): string { /* ... */ }\n\n// src/services/orderService.ts\nfunction formatDate(date: Date): string { /* ... */ } // Duplicate!\nfunction calculateTotal(items: Item[]): number { /* ... */ }\n\n// AFTER: Shared utilities extracted\n\n// src/shared/utils/date.ts\nexport function formatDate(date: Date): string { /* ... */ }\n\n// src/shared/utils/id.ts\nexport function generateId(): string { /* ... */ }\n\n// src/shared/utils/index.ts\nexport * from './date';\nexport * from './id';\n```\n\n---\n\n## Interface Extraction\n\n### Extract Interface for Decoupling\n\n```typescript\n// BEFORE: Direct class dependency\n// src/services/orderService.ts\nimport { UserService } from './userService';\n\nexport class OrderService {\n constructor(private userService: UserService) {}\n \n async createOrder(userId: string) {\n const user = await this.userService.getUser(userId);\n // ...\n }\n}\n\n// AFTER: Depend on interface, not implementation\n\n// src/interfaces/user.interface.ts\nexport interface IUserService {\n getUser(id: string): Promise\u003cUser>;\n createUser(data: CreateUserDto): Promise\u003cUser>;\n}\n\n// src/services/userService.ts\nimport { IUserService } from '../interfaces/user.interface';\n\nexport class UserService implements IUserService {\n async getUser(id: string): Promise\u003cUser> { /* ... */ }\n async createUser(data: CreateUserDto): Promise\u003cUser> { /* ... */ }\n}\n\n// src/services/orderService.ts\nimport { IUserService } from '../interfaces/user.interface';\n\nexport class OrderService {\n constructor(private userService: IUserService) {} // Interface, not class\n \n async createOrder(userId: string) {\n const user = await this.userService.getUser(userId);\n // ...\n }\n}\n```\n\n---\n\n## Layer Introduction\n\n### Add Service Layer\n\n```typescript\n// BEFORE: Business logic in controller\n// src/controllers/userController.ts\nexport async function createUser(req: Request, res: Response) {\n const { email, name, password } = req.body;\n \n // Validation\n if (!email || !isValidEmail(email)) {\n return res.status(400).json({ error: 'Invalid email' });\n }\n \n // Check duplicate\n const existing = await prisma.user.findUnique({ where: { email } });\n if (existing) {\n return res.status(409).json({ error: 'Email already exists' });\n }\n \n // Hash password\n const hashedPassword = await bcrypt.hash(password, 10);\n \n // Create user\n const user = await prisma.user.create({\n data: { email, name, password: hashedPassword },\n });\n \n // Send welcome email\n await sendEmail(email, 'Welcome!', welcomeTemplate(name));\n \n return res.status(201).json(user);\n}\n\n// AFTER: Controller delegates to service\n\n// src/services/user.service.ts\nexport class UserService {\n async createUser(data: CreateUserDto): Promise\u003cUser> {\n await this.validateEmail(data.email);\n await this.checkDuplicate(data.email);\n \n const hashedPassword = await this.hashPassword(data.password);\n const user = await this.userRepository.create({\n ...data,\n password: hashedPassword,\n });\n \n await this.emailService.sendWelcome(user);\n \n return user;\n }\n \n private async validateEmail(email: string): Promise\u003cvoid> {\n if (!isValidEmail(email)) {\n throw new ValidationError('Invalid email');\n }\n }\n \n private async checkDuplicate(email: string): Promise\u003cvoid> {\n const existing = await this.userRepository.findByEmail(email);\n if (existing) {\n throw new ConflictError('Email already exists');\n }\n }\n}\n\n// src/controllers/userController.ts\nexport async function createUser(req: Request, res: Response) {\n try {\n const user = await userService.createUser(req.body);\n return res.status(201).json(user);\n } catch (error) {\n return handleError(error, res);\n }\n}\n```\n\n### Add Repository Layer\n\n```typescript\n// BEFORE: Direct database access in service\n// src/services/userService.ts\nimport { prisma } from '../lib/prisma';\n\nexport class UserService {\n async getUser(id: string) {\n return prisma.user.findUnique({ where: { id } });\n }\n \n async createUser(data: CreateUserDto) {\n return prisma.user.create({ data });\n }\n}\n\n// AFTER: Repository abstracts database access\n\n// src/repositories/user.repository.ts\nexport class UserRepository {\n async findById(id: string): Promise\u003cUser | null> {\n return prisma.user.findUnique({ where: { id } });\n }\n \n async findByEmail(email: string): Promise\u003cUser | null> {\n return prisma.user.findUnique({ where: { email } });\n }\n \n async create(data: CreateUserData): Promise\u003cUser> {\n return prisma.user.create({ data });\n }\n \n async update(id: string, data: UpdateUserData): Promise\u003cUser> {\n return prisma.user.update({ where: { id }, data });\n }\n \n async delete(id: string): Promise\u003cvoid> {\n await prisma.user.delete({ where: { id } });\n }\n}\n\n// src/services/userService.ts\nexport class UserService {\n constructor(private userRepository: UserRepository) {}\n \n async getUser(id: string) {\n return this.userRepository.findById(id);\n }\n \n async createUser(data: CreateUserDto) {\n // Business logic here\n return this.userRepository.create(data);\n }\n}\n```\n\n---\n\n## Migration Strategies\n\n### Feature Flag Migration\n\n```typescript\n// Use feature flags to gradually migrate\n\n// src/config/features.ts\nexport const features = {\n useNewUserModule: process.env.USE_NEW_USER_MODULE === 'true',\n useNewOrderFlow: process.env.USE_NEW_ORDER_FLOW === 'true',\n};\n\n// src/services/index.ts\nimport { features } from '../config/features';\nimport { UserService as OldUserService } from './legacy/userService';\nimport { UserService as NewUserService } from '../modules/users/user.service';\n\nexport const userService = features.useNewUserModule\n ? new NewUserService()\n : new OldUserService();\n\n// Gradually enable in environments:\n// 1. Enable in development\n// 2. Enable in staging\n// 3. Enable for % of production traffic\n// 4. Enable for all production\n// 5. Remove old code\n```\n\n### Parallel Run Validation\n\n```typescript\n// Run both old and new code, compare results\n\nasync function migratedGetUser(id: string): Promise\u003cUser> {\n const [oldResult, newResult] = await Promise.all([\n oldUserService.getUser(id),\n newUserService.getUser(id),\n ]);\n \n // Compare results\n if (JSON.stringify(oldResult) !== JSON.stringify(newResult)) {\n logger.warn('Migration mismatch', {\n userId: id,\n old: oldResult,\n new: newResult,\n });\n \n // Return old result during validation period\n return oldResult;\n }\n \n // Results match, can use new\n return newResult;\n}\n```\n\n### Strangler Fig Pattern\n\n```\nPhase 1: New structure exists alongside old\n┌─────────────────────────────────────┐\n│ src/ │\n│ ├── services/ (OLD) │\n│ │ ├── userService.ts │\n│ │ └── orderService.ts │\n│ └── modules/ (NEW) │\n│ └── users/ │\n│ └── user.service.ts │\n└─────────────────────────────────────┘\n\nPhase 2: New consumers use new structure\n┌─────────────────────────────────────┐\n│ New code imports from modules/ │\n│ Old code still imports from │\n│ services/ (re-exports to modules/) │\n└─────────────────────────────────────┘\n\nPhase 3: Migrate existing consumers\n┌─────────────────────────────────────┐\n│ Update imports one by one │\n│ Run tests after each change │\n└─────────────────────────────────────┘\n\nPhase 4: Remove old structure\n┌─────────────────────────────────────┐\n│ src/ │\n│ └── modules/ (ONLY) │\n│ ├── users/ │\n│ └── orders/ │\n└─────────────────────────────────────┘\n```\n\n---\n\n## Common Refactoring Recipes\n\n### Recipe: Split God File\n\n```typescript\n// 1. Identify responsibilities in the file\n// src/services/userService.ts has:\n// - User CRUD\n// - Email sending\n// - Permission checking\n// - Password hashing\n\n// 2. Create new files for each responsibility\n// src/services/email.service.ts\n// src/services/permission.service.ts\n// src/utils/password.ts\n\n// 3. Extract functions one at a time\n// Move sendEmail to email.service.ts\n// Update imports in userService.ts\n// Run tests\n\n// 4. Repeat for each responsibility\n\n// 5. Final userService.ts only has user CRUD\n// and depends on extracted services\n```\n\n### Recipe: Flatten Deep Nesting\n\n```typescript\n// BEFORE: 6 levels deep\nsrc/features/users/components/forms/inputs/text/TextInput.tsx\n\n// Step 1: Identify actual usage patterns\n// - Is TextInput used only in user forms? → Keep nested\n// - Is TextInput used everywhere? → Move to shared\n\n// Step 2: If shared, move to shared/components\nsrc/shared/components/TextInput.tsx\n\n// Step 3: Update re-export for backward compatibility\n// src/features/users/components/forms/inputs/text/TextInput.tsx\nexport { TextInput } from '@/shared/components/TextInput';\n\n// Step 4: Update consumers gradually\n\n// Step 5: Remove re-export when all updated\n```\n\n### Recipe: Consolidate Duplicates\n\n```typescript\n// 1. Find duplicates\ngrep -r \"function formatDate\" src/\n\n// 2. Compare implementations\n// Are they identical? Slightly different? Very different?\n\n// 3. If identical: extract to shared\n// src/shared/utils/date.ts\nexport function formatDate(date: Date): string { /* ... */ }\n\n// 4. If slightly different: merge with options\nexport function formatDate(date: Date, options?: FormatOptions): string {\n const { locale = 'en-US', format = 'short' } = options ?? {};\n // ...\n}\n\n// 5. Update all usages\n// 6. Delete duplicates\n```\n\n### Recipe: Introduce Barrel Files\n\n```typescript\n// BEFORE: Import each file individually\nimport { UserService } from '../services/userService';\nimport { OrderService } from '../services/orderService';\nimport { ProductService } from '../services/productService';\n\n// AFTER: Single import from barrel\n\n// src/services/index.ts (barrel file)\nexport { UserService } from './userService';\nexport { OrderService } from './orderService';\nexport { ProductService } from './productService';\n\n// Consumer\nimport { UserService, OrderService, ProductService } from '../services';\n\n// ⚠️ Warning: Don't overuse barrels\n// Only create barrels for commonly imported together items\n// Avoid re-exporting everything (causes bundle bloat)\n```\n\n---\n\n## Safety Checklist\n\n### Before Refactoring\n\n- [ ] Tests exist and pass\n- [ ] Git working directory is clean\n- [ ] Branch created for refactoring\n- [ ] Team informed of changes\n\n### During Refactoring\n\n- [ ] One change at a time\n- [ ] Tests run after each change\n- [ ] Commit after each successful change\n- [ ] No behavior changes (only structural)\n\n### After Refactoring\n\n- [ ] All tests still pass\n- [ ] Application runs correctly\n- [ ] No console errors\n- [ ] PR reviewed by team\n- [ ] Documentation updated if needed\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":16879,"content_sha256":"761c7910b4ce9bca378babf70bcd7f0bcdcaffc6f9c96c4296efd145e039e291"},{"filename":"references/structural-patterns.md","content":"# Structural Patterns\n\nDirectory structures for different project types.\n\n## Frontend Applications\n\n### React/Next.js Feature-Based\n\n```\nsrc/\n├── app/ # Next.js App Router (or pages/)\n│ ├── (auth)/\n│ │ ├── login/\n│ │ └── register/\n│ ├── dashboard/\n│ └── layout.tsx\n│\n├── features/ # Feature modules\n│ ├── auth/\n│ │ ├── components/\n│ │ │ ├── LoginForm.tsx\n│ │ │ ├── RegisterForm.tsx\n│ │ │ └── index.ts\n│ │ ├── hooks/\n│ │ │ ├── useAuth.ts\n│ │ │ └── useSession.ts\n│ │ ├── api/\n│ │ │ └── auth.api.ts\n│ │ ├── types.ts\n│ │ ├── utils.ts\n│ │ └── index.ts\n│ │\n│ ├── users/\n│ │ ├── components/\n│ │ ├── hooks/\n│ │ ├── api/\n│ │ └── index.ts\n│ │\n│ └── orders/\n│ └── ...\n│\n├── shared/ # Shared across features\n│ ├── components/\n│ │ ├── ui/ # Generic UI (Button, Input, Modal)\n│ │ │ ├── Button.tsx\n│ │ │ ├── Input.tsx\n│ │ │ └── index.ts\n│ │ └── layout/ # Layout components\n│ │ ├── Header.tsx\n│ │ └── Sidebar.tsx\n│ ├── hooks/\n│ │ ├── useDebounce.ts\n│ │ └── useLocalStorage.ts\n│ ├── utils/\n│ │ ├── date.ts\n│ │ ├── format.ts\n│ │ └── validation.ts\n│ └── types/\n│ └── common.ts\n│\n├── lib/ # Third-party integrations\n│ ├── api-client.ts # Axios/fetch setup\n│ ├── query-client.ts # React Query setup\n│ └── analytics.ts\n│\n├── config/\n│ └── constants.ts\n│\n└── styles/\n └── globals.css\n```\n\n### Vue/Nuxt Feature-Based\n\n```\nsrc/\n├── pages/ # File-based routing\n├── features/\n│ ├── auth/\n│ │ ├── components/\n│ │ ├── composables/ # Vue composables (like hooks)\n│ │ ├── stores/ # Pinia stores\n│ │ └── index.ts\n│ └── users/\n├── shared/\n│ ├── components/\n│ ├── composables/\n│ └── utils/\n├── stores/ # Global stores\n└── plugins/\n```\n\n### Component Library\n\n```\nsrc/\n├── components/\n│ ├── Button/\n│ │ ├── Button.tsx\n│ │ ├── Button.test.tsx\n│ │ ├── Button.stories.tsx\n│ │ ├── Button.module.css\n│ │ └── index.ts\n│ ├── Input/\n│ ├── Modal/\n│ └── index.ts # Main export\n│\n├── hooks/\n│ ├── useClickOutside.ts\n│ └── index.ts\n│\n├── utils/\n│ └── cn.ts # className utility\n│\n├── types/\n│ └── common.ts\n│\n└── index.ts # Package entry point\n```\n\n---\n\n## Backend Applications\n\n### Express/Fastify Layered\n\n```\nsrc/\n├── controllers/ # HTTP layer\n│ ├── user.controller.ts\n│ ├── order.controller.ts\n│ └── index.ts\n│\n├── services/ # Business logic\n│ ├── user.service.ts\n│ ├── order.service.ts\n│ └── index.ts\n│\n├── repositories/ # Data access\n│ ├── user.repository.ts\n│ ├── order.repository.ts\n│ └── index.ts\n│\n├── models/ # Data structures\n│ ├── user.model.ts\n│ └── order.model.ts\n│\n├── middleware/\n│ ├── auth.middleware.ts\n│ ├── error.middleware.ts\n│ └── validation.middleware.ts\n│\n├── routes/\n│ ├── user.routes.ts\n│ ├── order.routes.ts\n│ └── index.ts\n│\n├── utils/\n│ ├── logger.ts\n│ └── errors.ts\n│\n├── types/\n│ └── index.ts\n│\n├── config/\n│ └── index.ts\n│\n├── database/\n│ ├── migrations/\n│ ├── seeds/\n│ └── connection.ts\n│\n└── app.ts\n```\n\n### NestJS Modular\n\n```\nsrc/\n├── modules/\n│ ├── auth/\n│ │ ├── auth.module.ts\n│ │ ├── auth.controller.ts\n│ │ ├── auth.service.ts\n│ │ ├── strategies/\n│ │ │ ├── jwt.strategy.ts\n│ │ │ └── local.strategy.ts\n│ │ ├── guards/\n│ │ │ └── jwt-auth.guard.ts\n│ │ ├── dto/\n│ │ │ ├── login.dto.ts\n│ │ │ └── register.dto.ts\n│ │ └── interfaces/\n│ │\n│ ├── users/\n│ │ ├── users.module.ts\n│ │ ├── users.controller.ts\n│ │ ├── users.service.ts\n│ │ ├── users.repository.ts\n│ │ ├── entities/\n│ │ │ └── user.entity.ts\n│ │ └── dto/\n│ │\n│ └── orders/\n│ └── ...\n│\n├── common/ # Shared across modules\n│ ├── decorators/\n│ ├── filters/\n│ ├── guards/\n│ ├── interceptors/\n│ ├── pipes/\n│ └── utils/\n│\n├── config/\n│ └── configuration.ts\n│\n├── database/\n│ ├── migrations/\n│ └── database.module.ts\n│\n├── app.module.ts\n└── main.ts\n```\n\n### Domain-Driven Design (DDD)\n\n```\nsrc/\n├── domain/ # Core business logic\n│ ├── user/\n│ │ ├── entities/\n│ │ │ └── User.ts\n│ │ ├── value-objects/\n│ │ │ ├── Email.ts\n│ │ │ └── UserId.ts\n│ │ ├── repositories/\n│ │ │ └── IUserRepository.ts\n│ │ ├── services/\n│ │ │ └── UserDomainService.ts\n│ │ └── events/\n│ │ └── UserCreatedEvent.ts\n│ │\n│ └── order/\n│ └── ...\n│\n├── application/ # Use cases\n│ ├── user/\n│ │ ├── commands/\n│ │ │ ├── CreateUserCommand.ts\n│ │ │ └── CreateUserHandler.ts\n│ │ └── queries/\n│ │ ├── GetUserQuery.ts\n│ │ └── GetUserHandler.ts\n│ │\n│ └── order/\n│\n├── infrastructure/ # External concerns\n│ ├── persistence/\n│ │ ├── repositories/\n│ │ │ └── UserRepository.ts # Implements IUserRepository\n│ │ └── orm/\n│ │ └── prisma/\n│ ├── messaging/\n│ │ └── EventBus.ts\n│ └── external-services/\n│ └── EmailService.ts\n│\n├── presentation/ # HTTP/API layer\n│ ├── controllers/\n│ ├── middleware/\n│ └── dto/\n│\n└── shared/\n ├── kernel/ # Base classes\n │ ├── Entity.ts\n │ ├── ValueObject.ts\n │ └── AggregateRoot.ts\n └── utils/\n```\n\n---\n\n## Full-Stack Applications\n\n### Next.js Full-Stack\n\n```\nsrc/\n├── app/ # Frontend pages + API routes\n│ ├── api/\n│ │ ├── users/\n│ │ │ └── route.ts\n│ │ └── orders/\n│ │ └── route.ts\n│ ├── (marketing)/\n│ │ └── page.tsx\n│ └── (app)/\n│ ├── dashboard/\n│ └── settings/\n│\n├── features/ # Shared frontend features\n│ └── ...\n│\n├── server/ # Backend logic\n│ ├── services/\n│ ├── repositories/\n│ └── db/\n│ └── schema.ts # Drizzle/Prisma schema\n│\n├── shared/ # Shared between client/server\n│ ├── types/\n│ └── validation/ # Zod schemas\n│\n└── lib/\n ├── db.ts\n └── auth.ts\n```\n\n### T3 Stack (Next.js + tRPC)\n\n```\nsrc/\n├── app/\n│ └── ...\n│\n├── server/\n│ ├── api/\n│ │ ├── routers/\n│ │ │ ├── user.ts\n│ │ │ ├── order.ts\n│ │ │ └── index.ts\n│ │ ├── trpc.ts\n│ │ └── root.ts\n│ └── db/\n│ └── schema.ts\n│\n├── features/\n│ └── ...\n│\n└── shared/\n └── ...\n```\n\n---\n\n## Monorepo Structures\n\n### Turborepo/Nx Monorepo\n\n```\nmy-monorepo/\n├── apps/\n│ ├── web/ # Next.js frontend\n│ │ ├── src/\n│ │ ├── package.json\n│ │ └── tsconfig.json\n│ ├── api/ # Backend API\n│ │ ├── src/\n│ │ └── package.json\n│ └── admin/ # Admin dashboard\n│ └── ...\n│\n├── packages/\n│ ├── ui/ # Shared UI components\n│ │ ├── src/\n│ │ │ ├── Button.tsx\n│ │ │ └── index.ts\n│ │ └── package.json\n│ ├── config/ # Shared configs\n│ │ ├── eslint/\n│ │ └── typescript/\n│ ├── utils/ # Shared utilities\n│ │ └── src/\n│ └── types/ # Shared types\n│ └── src/\n│\n├── package.json\n├── turbo.json\n└── pnpm-workspace.yaml\n```\n\n### Package Naming Convention\n\n```\n@myorg/ui # Shared UI\n@myorg/utils # Shared utilities\n@myorg/config # Shared configuration\n@myorg/types # Shared types\n@myorg/api-client # Generated API client\n@myorg/database # Database schema/client\n```\n\n---\n\n## Library/Package Structure\n\n### npm Package\n\n```\nmy-package/\n├── src/\n│ ├── index.ts # Main entry\n│ ├── core/\n│ │ ├── Client.ts\n│ │ └── types.ts\n│ ├── utils/\n│ │ └── helpers.ts\n│ └── errors/\n│ └── CustomError.ts\n│\n├── tests/\n│ ├── Client.test.ts\n│ └── helpers.test.ts\n│\n├── dist/ # Built output\n│ ├── index.js\n│ ├── index.d.ts\n│ └── index.mjs\n│\n├── package.json\n├── tsconfig.json\n├── tsup.config.ts # Build config\n└── README.md\n```\n\n### CLI Tool\n\n```\nmy-cli/\n├── src/\n│ ├── index.ts # Entry point\n│ ├── cli.ts # CLI setup (commander/yargs)\n│ ├── commands/\n│ │ ├── init.ts\n│ │ ├── build.ts\n│ │ └── deploy.ts\n│ ├── utils/\n│ │ ├── fs.ts\n│ │ └── logger.ts\n│ └── types/\n│ └── config.ts\n│\n├── templates/ # Template files for init\n│ └── ...\n│\n├── bin/\n│ └── cli.js # Executable entry\n│\n└── package.json\n```\n\n---\n\n## Test Organization\n\n### Colocated Tests (Recommended)\n\n```\nsrc/\n├── features/\n│ └── users/\n│ ├── components/\n│ │ ├── UserList.tsx\n│ │ └── UserList.test.tsx # Next to component\n│ ├── hooks/\n│ │ ├── useUsers.ts\n│ │ └── useUsers.test.ts\n│ └── user.service.ts\n│ user.service.test.ts\n```\n\n### Separate Test Directory\n\n```\nsrc/\n├── features/\n│ └── users/\n│ ├── components/\n│ └── hooks/\n│\ntests/\n├── unit/\n│ └── features/\n│ └── users/\n│ ├── UserList.test.tsx\n│ └── useUsers.test.ts\n├── integration/\n│ └── api/\n│ └── users.test.ts\n└── e2e/\n └── user-flow.test.ts\n```\n\n---\n\n## Configuration Files Organization\n\n### Root Level (Standard)\n\n```\nmy-project/\n├── .env # Environment (git-ignored)\n├── .env.example # Template\n├── .eslintrc.js\n├── .prettierrc\n├── .gitignore\n├── tsconfig.json\n├── package.json\n├── vitest.config.ts\n├── tailwind.config.js\n└── next.config.js\n```\n\n### Config Directory (For Complex)\n\n```\nmy-project/\n├── config/\n│ ├── eslint/\n│ │ ├── base.js\n│ │ └── react.js\n│ ├── typescript/\n│ │ ├── base.json\n│ │ └── react.json\n│ └── vitest/\n│ └── setup.ts\n│\n├── .eslintrc.js # extends from config/\n├── tsconfig.json # extends from config/\n└── vitest.config.ts # references config/\n```\n\n---\n\n## When to Choose Which Pattern\n\n| Project Type | Recommended Structure |\n|--------------|----------------------|\n| Small app (\u003c20 components) | Flat/simple |\n| Medium app (20-100 components) | Feature-based |\n| Large app (100+ components) | Feature-based with strict boundaries |\n| Component library | Component-per-folder |\n| REST API | Layered (controllers/services/repos) |\n| Complex domain | DDD |\n| Multiple apps | Monorepo |\n| npm package | Standard package structure |\n\n### Decision Factors\n\n**Use Feature-Based when:**\n- Multiple developers/teams\n- Features are independent\n- Features may be removed/added frequently\n- Code ownership matters\n\n**Use Layer-Based when:**\n- Small team\n- Features share lots of code\n- Traditional MVC background\n- Simpler mental model needed\n\n**Use DDD when:**\n- Complex business rules\n- Domain experts involved\n- Long-term maintainability critical\n- Multiple bounded contexts\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":13892,"content_sha256":"34b82f159fe7353e2562b70c5f92b1da153d59b8210d3c1c6b774149d39209bd"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Architecture Review","type":"text"}]},{"type":"paragraph","content":[{"text":"Analyze, audit, and improve project structure.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Key Principles","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Measure before changing","type":"text","marks":[{"type":"strong"}]},{"text":" — Map structure and identify concrete issues before proposing changes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Clear boundaries","type":"text","marks":[{"type":"strong"}]},{"text":" — Layers (UI, logic, data) separated with consistent dependency direction","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Colocation","type":"text","marks":[{"type":"strong"}]},{"text":" — Related code together; easy to find, change, and delete features","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Incremental migration","type":"text","marks":[{"type":"strong"}]},{"text":" — Refactor in phases, validate each step with tests","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quick Assessment","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"No circular dependencies","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Consistent directory naming and grouping (by feature or by type)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Single responsibility per file/module, reasonable file sizes (\u003c500 lines)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"External dependencies isolated, shared code properly extracted","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"New developers can navigate and find code for any feature easily","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quick Start Checklist","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Map current structure: directory tree, dependency graph, module boundaries","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Identify issues: circular deps, god modules, leaky abstractions, deep nesting","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Classify severity: critical (blocks dev), high (maintenance burden), medium/low (friction)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Propose target structure with migration plan","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Execute incrementally, validating with tests after each move","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"References","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Reference","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Description","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"analysis-techniques.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/analysis-techniques.md","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Dependency graphs, complexity metrics, code analysis","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"refactoring-patterns.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/refactoring-patterns.md","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Safe refactoring techniques, migration strategies","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"structural-patterns.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/structural-patterns.md","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Directory structures for different project types","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"dependency-management.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/dependency-management.md","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Circular deps, coupling, module boundaries","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cleanup-strategies.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/cleanup-strategies.md","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Dead code removal, consolidation, naming conventions","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"anti-rationalization.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/anti-rationalization.md","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Iron Law, common rationalizations, red flag STOP list for architecture discipline","type":"text"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"architecture-review","author":"@skillopedia","source":{"stars":7,"repo_name":"pokayokay","origin_url":"https://github.com/srstomp/pokayokay/blob/HEAD/plugins/pokayokay/skills/architecture-review/SKILL.md","repo_owner":"srstomp","body_sha256":"76e280b58c4152c51beadb57f242514e4f350086b3e1cc1f81425c2381876431","cluster_key":"9d134005757ffb3bdf1d2b2831a4f219049800e4181ff25d1a7f80cd79baec76","clean_bundle":{"format":"clean-skill-bundle-v1","source":"srstomp/pokayokay/plugins/pokayokay/skills/architecture-review/SKILL.md","attachments":[{"id":"800367be-3410-541b-a8fa-e8db918aaa8c","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/800367be-3410-541b-a8fa-e8db918aaa8c/attachment.md","path":"references/analysis-techniques.md","size":17003,"sha256":"31237a478ee89c5a23e271eceb1acb6416c9c24da728210a8b8366bb277d78f3","contentType":"text/markdown; charset=utf-8"},{"id":"7631c819-b228-5b83-a053-2d52cb357be9","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/7631c819-b228-5b83-a053-2d52cb357be9/attachment.md","path":"references/anti-rationalization.md","size":4919,"sha256":"bd43cbc8ffc42bbcd8ac5dd4a36a691044f73aab499a85d5db4f487b82294f42","contentType":"text/markdown; charset=utf-8"},{"id":"ecead469-c70a-5eb3-a17e-405bb3ffbdfe","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/ecead469-c70a-5eb3-a17e-405bb3ffbdfe/attachment.md","path":"references/cleanup-strategies.md","size":15288,"sha256":"f1439129a44dedfa6760af75532f11903ea496c0c9357407f4f064346f919ef2","contentType":"text/markdown; charset=utf-8"},{"id":"852cb01e-660b-5400-b615-659e24181e90","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/852cb01e-660b-5400-b615-659e24181e90/attachment.md","path":"references/dependency-management.md","size":15641,"sha256":"2b5b60b461aaf5d0e4f6ee62a5dd1d34f19c6e075817fd65a2ad0ab69a76c719","contentType":"text/markdown; charset=utf-8"},{"id":"dbd1b184-98a8-5208-980e-5aac98b0299f","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/dbd1b184-98a8-5208-980e-5aac98b0299f/attachment.md","path":"references/refactoring-patterns.md","size":16879,"sha256":"761c7910b4ce9bca378babf70bcd7f0bcdcaffc6f9c96c4296efd145e039e291","contentType":"text/markdown; charset=utf-8"},{"id":"cb70f09d-2385-5030-955d-894ee579e98b","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/cb70f09d-2385-5030-955d-894ee579e98b/attachment.md","path":"references/structural-patterns.md","size":13892,"sha256":"34b82f159fe7353e2562b70c5f92b1da153d59b8210d3c1c6b774149d39209bd","contentType":"text/markdown; charset=utf-8"}],"bundle_sha256":"7f007eee89b07de487fd8c639e264e2415f063b19931e1cdb64f6ece709b8a80","attachment_count":6,"text_attachments":6,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"plugins/pokayokay/skills/architecture-review/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"security","category_label":"Security"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"security","import_tag":"clean-skills-v1","description":"Use when auditing project structure, planning refactors, improving code organization, analyzing dependencies and module boundaries, or identifying structural issues. TypeScript/JavaScript-primary with language-agnostic patterns."}},"renderedAt":1782989537518}

Architecture Review Analyze, audit, and improve project structure. Key Principles - Measure before changing — Map structure and identify concrete issues before proposing changes - Clear boundaries — Layers (UI, logic, data) separated with consistent dependency direction - Colocation — Related code together; easy to find, change, and delete features - Incremental migration — Refactor in phases, validate each step with tests Quick Assessment - No circular dependencies - Consistent directory naming and grouping (by feature or by type) - Single responsibility per file/module, reasonable file size…