# CLAUDE.md - Developer Documentation ## Project Overview **Datacenter Designer** is a web-based visual design tool for datacenter infrastructure. It allows users to create, manage, and visualize rack layouts, network devices, and their interconnections in both physical and logical views. ### Core Purpose - Visual rack layout planning (physical positioning) - Device placement within racks (U1-U42 slots with multi-unit form factors) - Network connection mapping between devices - Logical topology view (independent of physical layout) - Export/import for data portability ### Technology Stack - **Frontend**: Vanilla JavaScript (ES6 modules), Konva.js (canvas library), ag-Grid (tables), SheetJS (Excel export) - **Backend**: Node.js, Express 4.x - **Database**: SQLite3 - **No build process**: Direct ES6 modules, no bundler required --- ## Architecture ### High-Level Structure ``` ┌─────────────────────────────────────────────────┐ │ Browser │ │ ┌────────────────────────────────────────────┐ │ │ │ app.js (Main Controller) │ │ │ │ - Orchestrates all managers │ │ │ │ - Handles modals and UI │ │ │ │ - API client │ │ │ │ - View switching (Physical/Logical) │ │ │ └────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ ▼ ▼ ▼ ▼ │ │ ┌────────┐ ┌─────────┐ ┌─────────┐ ┌────────┐ │ │ │ Rack │ │ Device │ │Connect │ │ Table │ │ │ │Manager │ │Manager │ │Manager │ │Manager │ │ │ └────────┘ └─────────┘ └─────────┘ └────────┘ │ │ │ │ │ │ │ │ └──────────┴───────────┴──────────┘ │ │ │ │ │ Konva.js Canvas │ └────────────────────│──────────────────────────────┘ │ HTTP/REST API ┌────────────────────▼──────────────────────────────┐ │ Server │ │ ┌──────────────────────────────────────────────┐│ │ │ server.js (Express Router) ││ │ │ - RESTful endpoints ││ │ │ - Request/response handling ││ │ └──────────────────────────────────────────────┘│ │ │ │ │ ┌──────────────────▼──────────────────────────┐ │ │ │ db.js (Database Layer) │ │ │ │ - Promise-wrapped SQLite operations │ │ │ │ - Schema management │ │ │ └──────────────────────────────────────────────┘ │ │ │ │ │ SQLite Database File │ └───────────────────────────────────────────────────┘ ``` ### File Organization ``` datacenter-designer/ ├── server/ │ ├── server.js (276 LOC) - Express routes │ └── db.js (547 LOC) - Database operations ├── public/ │ ├── index.html (193 LOC) - Main HTML structure │ ├── css/ │ │ └── style.css (741 LOC) - All styles │ └── js/ │ ├── app.js (1719 LOC) - Main controller │ ├── rack-manager.js (488 LOC) - Rack rendering/interaction │ ├── device-manager.js (513 LOC) - Device rendering/interaction │ ├── connection-manager.js (901 LOC) - Connection lines/waypoints │ └── table-manager.js (792 LOC) - ag-Grid table views ├── database/ │ └── datacenter.db (Created at runtime) ├── package.json └── README.md Total: ~5,236 lines of code ``` --- ## Critical Review ### ✅ Strengths 1. **Clean Separation of Concerns**: Manager pattern isolates rack, device, connection, and table logic 2. **Simple Tech Stack**: No build process, direct ES6 modules, minimal dependencies 3. **RESTful API**: Clear HTTP API with predictable endpoints 4. **SQLite Persistence**: Appropriate for local/desktop deployment 5. **Konva.js Integration**: Good choice for canvas-based diagramming 6. **Dual View System**: Physical (rack-based) and logical (topology) views ### ❌ Issues & Anti-Patterns #### 1. **Monolithic `app.js` (1719 lines)** - **Violation**: Single Responsibility Principle - **Contains**: API client, modal management, zoom/pan, view switching, event coordination, export/import - **Should be**: Split into smaller modules (API client, ModalManager, StateManager, UIController) #### 2. **Repetitive Code (DRY Violations)** ```javascript // Repeated everywhere in server.js: try { // ... logic } catch (err) { res.status(500).json({ error: err.message }); } // Repeated modal patterns in app.js modal.classList.remove('hidden'); // ...setup modal.classList.add('hidden'); ``` #### 3. **Database Layer Issues** - **Callback-based sqlite3**: Manually wrapping every query in Promises - **No migration system**: Schema changes via ALTER TABLE with error swallowing (lines 106-140 in db.js) - **Verbose**: Every CRUD operation is 10-15 lines of boilerplate - **Better alternative**: `better-sqlite3` (synchronous, simpler, faster) #### 4. **Hard-Coded Magic Numbers** ```javascript // Scattered throughout codebase: const maxSlots = 42; // Rack slots const rackWidth = 520; // Rack dimensions const rackHeight = 1510; const gridSize = 600; // Grid spacing const deviceHeight = 32; const deviceSpacing = 2; const topMargin = 10; ``` **Should be**: Centralized in `config.js` with semantic names #### 5. **API Client Design** ```javascript class API { // One method per endpoint - not scalable getRacks() { return this.request('/api/racks?projectId=...'); } createRack(...) { return this.request(...); } updateRackPosition(...) { return this.request(...); } // ... 30+ methods } ``` **Should be**: Generic resource methods or use a library #### 6. **CSS Organization** - **741 lines in one file**: No modularity - **Hard-coded colors**: `#4A90E2`, `#f5f5f5`, etc. repeated - **No CSS variables**: Should use `--primary-color`, `--bg-color`, etc. - **No responsiveness**: No media queries, fixed dimensions - **No dark mode support**: Hard-coded light theme only #### 7. **State Management** - **Scattered state**: Each manager holds its own state in Maps - **DOM as state**: Using localStorage without versioning - **No synchronization**: Manual `canvas-data-changed` events - **No undo/redo**: No state history #### 8. **Input Validation** - **Server**: Minimal validation (trusts client) - **Client**: No form validation, uses `prompt()` for input - **No schema validation**: No Zod, Joi, or similar #### 9. **Error Handling** ```javascript // Current: catch (err) { console.error('Failed:', err); alert('Failed: ' + err.message); } ``` **Should be**: Toast notifications, user-friendly messages, error boundaries #### 10. **Export/Import** - **No versioning**: Export format has version field but isn't checked properly - **Monolithic**: One giant JSON blob - **No incremental import**: All-or-nothing ### ⚠️ Over-Engineering 1. **View-Specific Waypoints**: `waypoints_physical` and `waypoints_logical` stored separately - **Better**: Store once, transform with view matrix 2. **Separate `rack_units` column**: Could be derived from `device_type` 3. **Multiple modal patterns**: Overlapping modal handling code ### ⚠️ Under-Engineering 1. **No undo/redo**: Critical for a design tool 2. **No keyboard shortcuts**: Only `Esc` and `Del` supported 3. **No search/filter**: As data grows, navigation becomes difficult 4. **No loading states**: UI freezes during operations 5. **No optimistic updates**: Waits for server before updating UI 6. **No batch operations**: Can't select multiple racks/devices 7. **No auto-save**: Only manual saves via export --- ## Better Technologies / Alternatives ### Database **Current**: `sqlite3` (callback-based) **Better**: `better-sqlite3` - Synchronous API (simpler code) - 2-3x faster - No callback hell ```javascript // Current: return new Promise((resolve, reject) => { this.db.get('SELECT * FROM racks WHERE id = ?', [id], (err, row) => { if (err) reject(err); else resolve(row); }); }); // With better-sqlite3: return db.prepare('SELECT * FROM racks WHERE id = ?').get(id); ``` ### State Management **Current**: Scattered Maps in each manager **Better Options**: 1. **Zustand** (100 lines, minimal API) 2. **Valtio** (proxy-based reactivity) 3. **Nanostores** (atomic stores) ### API Client **Current**: Custom 30+ method API class **Better**: **ky** or **axios** with interceptors ```javascript // Generic resource client: const api = { get: (url) => ky.get(url).json(), post: (url, data) => ky.post(url, { json: data }).json(), // ... + error handling in interceptors }; ``` ### CSS Organization **Current**: 741-line monolithic file **Better**: Split by concern + CSS variables ```css /* config.css */ :root { --primary-color: #4A90E2; --bg-color: #f5f5f5; --rack-width: 520px; --rack-height: 1510px; } /* components/rack.css */ /* components/device.css */ /* layout.css */ /* theme.css */ ``` ### Configuration **Current**: Hard-coded everywhere **Better**: `config.js` ```javascript export const RACK_CONFIG = { WIDTH: 520, HEIGHT: 1510, SLOTS: 42, MARGIN: { top: 10, right: 10, bottom: 10, left: 10 } }; export const GRID_CONFIG = { HORIZONTAL: 600, VERTICAL: 1610 }; ``` ### Validation **Current**: None **Better**: **Zod** for schema validation ```javascript const RackSchema = z.object({ name: z.string().min(1).max(50), x: z.number().finite(), y: z.number().finite() }); ``` --- ## Recommended Refactoring Strategy ### Option A: In-Place Refactoring (Direct Edit) **Pros**: - Keep git history - Incremental changes - Can test at each step **Cons**: - Risk of breaking working features - Harder to compare old vs new - No fallback ### Option B: Release Candidate Approach (Recommended) **Pros**: - Clean slate while keeping original - Can compare side-by-side - Easy to revert - Clear migration path **Cons**: - Duplicated files temporarily - Need to sync any new features **Proposed Structure**: ``` datacenter-designer/ ├── rc/ # New refactored version │ ├── server/ │ │ ├── config.js # NEW: Configuration │ │ ├── db.js # REFACTORED: better-sqlite3 │ │ ├── routes/ # NEW: Split routes │ │ │ ├── projects.js │ │ │ ├── racks.js │ │ │ ├── devices.js │ │ │ └── connections.js │ │ └── server.js # SIMPLIFIED: Just setup │ ├── public/ │ │ ├── index.html # UPDATED: More semantic │ │ ├── css/ │ │ │ ├── config.css # NEW: CSS variables │ │ │ ├── layout.css │ │ │ ├── components.css │ │ │ └── theme.css │ │ └── js/ │ │ ├── config.js # NEW: Constants │ │ ├── lib/ │ │ │ ├── api.js # REFACTORED: Simplified │ │ │ ├── state.js # NEW: State manager │ │ │ └── ui.js # NEW: UI utilities │ │ ├── managers/ │ │ │ ├── rack-manager.js │ │ │ ├── device-manager.js │ │ │ ├── connection-manager.js │ │ │ └── table-manager.js │ │ └── app.js # SLIMMED: Orchestrator only │ └── database/ │ └── .gitkeep ├── server/ # OLD: Keep during transition ├── public/ # OLD: Keep during transition ├── .gitignore ├── CLAUDE.md # This file ├── README.md └── package.json ``` --- ## Refactoring Checklist ### Phase 1: Foundation (Day 1-2) - [ ] Create `rc/` directory structure - [ ] Setup `.gitignore` properly - [ ] Create `rc/server/config.js` with all constants - [ ] Create `rc/public/js/config.js` with frontend constants - [ ] Port database to `better-sqlite3` - [ ] Create migration system - [ ] Split CSS into modules with CSS variables - [ ] Make layout responsive (media queries) ### Phase 2: Backend (Day 3) - [ ] Split routes into separate files - [ ] Add input validation (Zod or similar) - [ ] Implement error middleware - [ ] Add request logging - [ ] Create API documentation (OpenAPI/Swagger) ### Phase 3: Frontend Core (Day 4-5) - [ ] Extract API client to `lib/api.js` - [ ] Extract state management to `lib/state.js` - [ ] Extract UI utilities to `lib/ui.js` (modal manager, toast, etc.) - [ ] Slim down `app.js` to orchestration only - [ ] Refactor managers to use new state system ### Phase 4: Features & UX (Day 6-7) - [ ] Add toast notifications (replace `alert()`) - [ ] Add loading states - [ ] Add keyboard shortcuts - [ ] Add undo/redo system - [ ] Add search/filter - [ ] Add batch operations - [ ] Improve error messages ### Phase 5: Testing & Documentation (Day 8) - [ ] Add unit tests for backend - [ ] Add integration tests - [ ] Update README.md - [ ] Update CLAUDE.md - [ ] Add inline JSDoc comments - [ ] Performance testing ### Phase 6: Migration (Day 9-10) - [ ] Test thoroughly - [ ] Migrate data from old DB if needed - [ ] Move `rc/` to root - [ ] Archive old code to `old/` - [ ] Update package.json scripts - [ ] Final testing --- ## Key Principles to Follow ### KISS (Keep It Simple, Stupid) - Avoid abstractions unless proven necessary - Prefer composition over inheritance - Use vanilla JS unless library provides clear value ### DRY (Don't Repeat Yourself) - Extract repeated patterns (error handling, modal management) - Use constants instead of magic numbers - Create reusable utility functions ### SOLID Principles - **S**: Single Responsibility - Each module does one thing - **O**: Open/Closed - Extend without modifying - **L**: Liskov Substitution - Subtypes must be substitutable - **I**: Interface Segregation - Many specific interfaces > one general - **D**: Dependency Inversion - Depend on abstractions ### WORM (Write Once, Read Many) - Optimize for read performance - Use indices on frequently queried columns - Cache frequently accessed data - Minimize database writes ### Additional Principles - **Fail Fast**: Validate early, throw errors quickly - **Convention over Configuration**: Sensible defaults - **Progressive Enhancement**: Works without JS, enhanced with it - **Accessibility**: Keyboard navigation, ARIA labels, screen reader support --- ## Responsive Design Strategy ### Breakpoints ```css /* Mobile: < 768px */ @media (max-width: 767px) { /* Stack toolbar items, hide non-essential controls */ } /* Tablet: 768px - 1024px */ @media (min-width: 768px) and (max-width: 1024px) { /* Optimize for touch, larger buttons */ } /* Desktop: > 1024px */ @media (min-width: 1025px) { /* Full feature set */ } ``` ### Layout Strategies 1. **Toolbar**: Collapse to hamburger menu on mobile 2. **Canvas**: Always full viewport minus toolbar 3. **Tables**: Horizontal scroll on mobile, fixed on desktop 4. **Modals**: Full-screen on mobile, centered on desktop 5. **Context Menus**: Bottom sheet on mobile, popup on desktop ### Touch Support - Increase hit targets to 44x44px minimum - Add touch gestures (pinch-zoom, two-finger pan) - Show hover states on touch as active states - Use native select/input elements on mobile --- ## Performance Considerations ### Canvas Rendering - Use `batchDraw()` instead of `draw()` for multiple updates - Implement viewport culling (don't render off-screen items) - Use `cache()` for static shapes - Debounce pan/zoom updates ### Database - Add indices on foreign keys - Use transactions for bulk operations - Implement connection pooling (if moving to client-server) - Lazy-load connections (don't load all at startup) ### Network - Implement request debouncing for auto-save - Use HTTP caching headers - Compress API responses (gzip) - Implement pagination for large datasets --- ## Security Considerations ### SQL Injection - ✅ Already using parameterized queries - [ ] Add input sanitization layer - [ ] Validate all inputs on server ### XSS (Cross-Site Scripting) - [ ] Sanitize user input before displaying - [ ] Use `textContent` instead of `innerHTML` where possible - [ ] Add Content Security Policy headers ### CSRF (Cross-Site Request Forgery) - [ ] Add CSRF tokens for state-changing operations - [ ] Use SameSite cookies ### File Upload - If adding import from file: - [ ] Validate file size - [ ] Validate file type - [ ] Scan for malicious content --- ## .gitignore Strategy To avoid pushing sensitive or generated files: ```gitignore # Dependencies node_modules/ package-lock.json # Optional: some include, some exclude # Database (user data) database/*.db database/*.db-shm database/*.db-wal *.db *.db-shm *.db-wal # Logs logs/ *.log npm-debug.log* # Environment variables .env .env.local .env.*.local # IDE .vscode/ .idea/ *.swp *.swo *~ .DS_Store # Build outputs (if added later) dist/ build/ .cache/ # Temporary files tmp/ temp/ *.tmp # OS files Thumbs.db .DS_Store # Claude-specific (optional) .claude/ ``` **Important**: If database contains sample data for demonstrations, create a separate `database/sample.db` and explicitly include it: ```gitignore # Ignore user databases database/*.db # But include sample !database/sample.db ``` --- ## Testing Strategy ### Unit Tests - Test database operations in isolation - Test utility functions - Test state management - Use: **Vitest** or **Jest** ### Integration Tests - Test API endpoints - Test full CRUD workflows - Use: **Supertest** + **Vitest** ### E2E Tests - Test critical user journeys - Test cross-browser compatibility - Use: **Playwright** or **Cypress** ### Test Structure ```javascript // Example: tests/db.test.js import { describe, it, expect, beforeEach } from 'vitest'; import db from '../server/db.js'; describe('Database - Racks', () => { beforeEach(() => { // Reset database to known state }); it('should create a rack', () => { const rack = db.createRack(1, 'RACK01', 0, 0); expect(rack.id).toBeDefined(); expect(rack.name).toBe('RACK01'); }); it('should not create duplicate rack names in same project', () => { db.createRack(1, 'RACK01', 0, 0); expect(() => db.createRack(1, 'RACK01', 100, 0)).toThrow(); }); }); ``` --- ## Future Enhancements Roadmap ### Phase 1: Core UX Improvements - [ ] Undo/redo system - [ ] Enhanced keyboard shortcuts - [ ] Toast notifications (replace browser alerts) - [ ] Loading states - [ ] Search and filter functionality - [ ] Batch operations (select multiple items) - [ ] Auto-save functionality ### Phase 2: Multi-User Support - [ ] User management system - [ ] Authentication and authorization - [ ] OIDC-compatible external SSO integration - [ ] Project sharing between users - [ ] Role-based access control (view/edit/admin) - [ ] User profile management ### Phase 3: Collaboration - [ ] Real-time collaborative editing (WebSocket) - [ ] Concurrent access management - [ ] User presence indicators - [ ] Change notifications - [ ] Conflict resolution - [ ] Version history / snapshots - [ ] Activity audit logging ### Phase 4: Advanced Features - [ ] Custom device types (user-defined) - [ ] Cable labeling and management - [ ] VLAN visualization - [ ] IP address management - [ ] Documentation generation (diagrams, BOMs) - [ ] Import from other formats (Visio, Lucidchart) - [ ] PostgreSQL/MySQL support ### Phase 5: Platform Enhancements - [ ] Dark mode - [ ] Mobile/tablet responsive design - [ ] 3D rack visualization - [ ] Cable routing visualization - [ ] Enhanced export formats - [ ] API for 3rd party integrations - [ ] Backup/restore automation --- ## Common Gotchas & Pitfalls ### Konva-Specific 1. **Coordinate Systems**: Konva uses top-left origin, racks use bottom-up slot numbering (U1 at bottom) 2. **Event Bubbling**: Events on canvas can propagate unexpectedly - use `e.cancelBubble = true` 3. **Memory Leaks**: Always destroy unused layers/shapes 4. **Performance**: Too many shapes? Use `virtualizer` pattern ### SQLite-Specific 1. **Foreign Keys**: Must enable explicitly with `PRAGMA foreign_keys = ON` 2. **Concurrency**: Only one write at a time - queue writes or use WAL mode 3. **Migrations**: No built-in system - roll your own or use library 4. **Type System**: Dynamic typing can surprise you (stores as INTEGER, returns as Number) ### CSS/Canvas Interaction 1. **Canvas Size**: Must set both CSS size and Konva stage size 2. **DPI Scaling**: High-DPI displays may need pixel ratio adjustment 3. **Touch Events**: Handle both mouse and touch events separately --- ## Contributing Guidelines ### Code Style - **Indentation**: 2 spaces - **Quotes**: Single quotes for strings - **Semicolons**: Required - **Naming**: camelCase for variables/functions, PascalCase for classes - **Line Length**: 100 characters max - **Comments**: JSDoc for public APIs, inline for complex logic ### Commit Messages Follow Conventional Commits: ``` feat: add undo/redo system fix: correct device positioning in logical view docs: update CLAUDE.md with testing strategy refactor: extract API client to separate file test: add unit tests for database operations chore: update dependencies ``` ### Pull Request Process 1. Create feature branch from `main` 2. Make changes with tests 3. Update documentation 4. Run linter and tests 5. Submit PR with description 6. Address review comments 7. Merge when approved --- ## Debugging Tips ### Backend Debugging ```bash # Enable SQLite query logging DEBUG=sqlite3 npm start # Enable Express debug logging DEBUG=express:* npm start # Enable all debug logging DEBUG=* npm start ``` ### Frontend Debugging ```javascript // Enable Konva debugging Konva.showWarnings = true; // Log all API calls api.request = new Proxy(api.request, { apply(target, thisArg, args) { console.log('[API]', args[0], args[1]); return target.apply(thisArg, args); } }); ``` ### Common Issues 1. **Canvas not updating**: Call `.batchDraw()` on layer 2. **Events not firing**: Check if shape is `listening(true)` 3. **Drag not working**: Check if shape is `draggable(true)` and parent layer is listening 4. **Database locked**: Close all connections, check for transactions 5. **CORS errors**: Ensure frontend and backend are on same origin or CORS is enabled --- ## Glossary - **Rack**: Physical equipment cabinet with 42U slots - **U / Rack Unit**: Standard height measurement (1U = 1.75 inches) - **Slot**: Position within a rack (U1 at bottom, U42 at top) - **Device**: Network equipment (switch, router, firewall, etc.) - **Form Factor**: Device height in rack units (1U, 2U, 4U, etc.) - **Connection**: Network link between two device ports - **Waypoint**: Intermediate point in a connection line for routing - **Physical View**: Rack-based layout showing physical positioning - **Logical View**: Topology view ignoring physical constraints - **Project**: Isolated workspace containing racks, devices, connections - **Canvas**: Konva.js drawing surface - **Stage**: Top-level Konva container - **Layer**: Konva organizational unit (rack layer, device layer, connection layer) - **Shape**: Individual Konva element (rectangle, text, line, etc.) --- ## Links & Resources ### Dependencies - [Konva.js Documentation](https://konvajs.org/docs/) - [ag-Grid Documentation](https://www.ag-grid.com/javascript-data-grid/) - [SheetJS Documentation](https://docs.sheetjs.com/) - [SQLite Documentation](https://www.sqlite.org/docs.html) - [better-sqlite3](https://github.com/WiseLibs/better-sqlite3) ### Design Patterns - [JavaScript Design Patterns](https://www.patterns.dev/) - [SOLID Principles](https://www.digitalocean.com/community/conceptual_articles/s-o-l-i-d-the-first-five-principles-of-object-oriented-design) - [Martin Fowler - Refactoring](https://refactoring.com/) ### Best Practices - [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript) - [Clean Code JavaScript](https://github.com/ryanmcdermott/clean-code-javascript) - [Web Performance Best Practices](https://web.dev/fast/) --- ## Revision History | Version | Date | Author | Changes | |---------|------|--------|---------| | 0.1.0 | 2025-10-26 | Claude | Initial release - comprehensive documentation | --- ## License MIT License - See LICENSE file for details