Files
datacenter-designer/CLAUDE.md
Stefano Manfredi 3431a121a9 First commit
2025-10-27 11:57:38 +00:00

26 KiB

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)

// 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

// 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

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

// 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
// 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

// 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

/* 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

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

const RackSchema = z.object({
  name: z.string().min(1).max(50),
  x: z.number().finite(),
  y: z.number().finite()
});

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

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

/* 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:

# 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:

# 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

// 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

# 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

// 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.)

Dependencies

Design Patterns

Best Practices


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