Files
Filamenteka/docs/DATA_STRUCTURE_PROPOSAL.md
DaX 18110ab159 Major restructure: Remove Confluence, add V2 data structure, organize for dev/prod
- Import real data from PDF (35 Bambu Lab filaments)
- Remove all Confluence integration and dependencies
- Implement new V2 data structure with proper inventory tracking
- Add backwards compatibility for existing data
- Create enhanced UI components (ColorSwatch, InventoryBadge, MaterialBadge)
- Add advanced filtering with quick filters and multi-criteria search
- Organize codebase for dev/prod environments
- Update Lambda functions to support both V1/V2 formats
- Add inventory summary dashboard
- Clean up project structure and documentation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 01:12:50 +02:00

5.9 KiB

Improved Data Structure Proposal

Current Issues

  1. Mixed languages (English/Serbian)
  2. String fields for numeric/boolean values
  3. Inconsistent status representation
  4. No proper inventory tracking
  5. Missing important metadata

Proposed Structure

interface Filament {
  // Identifiers
  id: string;
  sku?: string;  // For internal tracking
  
  // Product Info
  brand: string;
  type: 'PLA' | 'PETG' | 'ABS' | 'TPU' | 'SILK' | 'CF' | 'WOOD';
  material: {
    base: 'PLA' | 'PETG' | 'ABS' | 'TPU';
    modifier?: 'Silk' | 'Matte' | 'Glow' | 'Wood' | 'CF';
  };
  color: {
    name: string;
    hex?: string;      // Color code for UI display
    pantone?: string;  // For color matching
  };
  
  // Physical Properties
  weight: {
    value: number;     // 1000 for 1kg, 500 for 0.5kg
    unit: 'g' | 'kg';
  };
  diameter: number;    // 1.75 or 2.85
  
  // Inventory Status
  inventory: {
    total: number;     // Total spools
    available: number; // Available for use
    inUse: number;     // Currently being used
    locations: {
      vacuum: number;  // In vacuum storage
      opened: number;  // Opened but usable
      printer: number; // Loaded in printer
    };
  };
  
  // Purchase Info
  pricing: {
    purchasePrice?: number;
    currency: 'RSD' | 'EUR' | 'USD';
    supplier?: string;
    purchaseDate?: string;
  };
  
  // Condition
  condition: {
    isRefill: boolean;
    openedDate?: string;
    expiryDate?: string;
    storageCondition: 'vacuum' | 'sealed' | 'opened' | 'desiccant';
    humidity?: number;  // Last measured
  };
  
  // Metadata
  tags: string[];      // ['premium', 'engineering', 'easy-print']
  notes?: string;      // Special handling instructions
  images?: string[];   // S3 URLs for photos
  
  // Timestamps
  createdAt: string;
  updatedAt: string;
  lastUsed?: string;
}

Benefits

1. Better Filtering

// Find all sealed PLA under 1kg
filaments.filter(f => 
  f.material.base === 'PLA' && 
  f.weight.value <= 1000 && 
  f.condition.storageCondition === 'vacuum'
)

2. Inventory Management

// Get total available filament weight
const totalWeight = filaments.reduce((sum, f) => 
  sum + (f.inventory.available * f.weight.value), 0
);

// Find low stock items
const lowStock = filaments.filter(f => 
  f.inventory.available <= 1 && f.inventory.total > 0
);

3. Color Management

// Group by color for visualization
const colorGroups = filaments.reduce((groups, f) => {
  const color = f.color.name;
  groups[color] = groups[color] || [];
  groups[color].push(f);
  return groups;
}, {});

4. Usage Tracking

// Find most used filaments
const mostUsed = filaments
  .filter(f => f.lastUsed)
  .sort((a, b) => new Date(b.lastUsed) - new Date(a.lastUsed))
  .slice(0, 10);

Migration Strategy

Phase 1: Add New Fields (Non-breaking)

// Update Lambda to handle both old and new structure
const migrateFilament = (old) => ({
  ...old,
  material: {
    base: old.tip || 'PLA',
    modifier: old.finish !== 'Basic' ? old.finish : undefined
  },
  color: {
    name: old.boja
  },
  weight: {
    value: 1000, // Default 1kg
    unit: 'g'
  },
  inventory: {
    total: parseInt(old.kolicina) || 1,
    available: old.otvoreno ? 0 : 1,
    inUse: 0,
    locations: {
      vacuum: old.vakum ? 1 : 0,
      opened: old.otvoreno ? 1 : 0,
      printer: 0
    }
  },
  condition: {
    isRefill: old.refill === 'Da',
    storageCondition: old.vakum ? 'vacuum' : (old.otvoreno ? 'opened' : 'sealed')
  }
});

Phase 2: Update UI Components

  • Create new filter components for material type
  • Add inventory status indicators
  • Color preview badges
  • Storage condition icons

Phase 3: Enhanced Features

  1. Barcode/QR Integration: Generate QR codes for each spool
  2. Usage History: Track which prints used which filament
  3. Alerts: Low stock, expiry warnings
  4. Analytics: Cost per print, filament usage trends

DynamoDB Optimization

Current Indexes

  • brand-index
  • tip-index
  • status-index

Proposed Indexes

global_secondary_index {
  name = "material-color-index"
  hash_key = "material.base"
  range_key = "color.name"
}

global_secondary_index {
  name = "inventory-status-index"
  hash_key = "condition.storageCondition"
  range_key = "inventory.available"
}

global_secondary_index {
  name = "brand-type-index"
  hash_key = "brand"
  range_key = "material.base"
}

Example Queries

Find all available green filaments

const greenFilaments = await dynamodb.query({
  IndexName: 'material-color-index',
  FilterExpression: 'contains(color.name, :green) AND inventory.available > :zero',
  ExpressionAttributeValues: {
    ':green': 'Green',
    ':zero': 0
  }
}).promise();

Get inventory summary

const summary = await dynamodb.scan({
  TableName: TABLE_NAME,
  ProjectionExpression: 'brand, material.base, inventory'
}).promise();

const report = summary.Items.reduce((acc, item) => {
  const key = `${item.brand}-${item.material.base}`;
  acc[key] = (acc[key] || 0) + item.inventory.total;
  return acc;
}, {});

UI Improvements

1. Visual Inventory Status

<div className="flex gap-2">
  {filament.inventory.locations.vacuum > 0 && (
    <Badge icon="vacuum" count={filament.inventory.locations.vacuum} />
  )}
  {filament.inventory.locations.opened > 0 && (
    <Badge icon="box-open" count={filament.inventory.locations.opened} />
  )}
</div>

2. Color Swatches

<div 
  className="w-8 h-8 rounded-full border-2"
  style={{ backgroundColor: filament.color.hex || getColorFromName(filament.color.name) }}
  title={filament.color.name}
/>

3. Smart Filters

  • Quick filters: "Ready to use", "Low stock", "Refills only"
  • Material groups: "Standard PLA", "Engineering", "Specialty"
  • Storage status: "Vacuum sealed", "Open spools", "In printer"

Would you like me to implement this improved structure?