Clean up fake colors and add missing Bambu Lab colors
- Add migration 023: delete 67 fake colors, rename IronGray typo, add 16 missing real colors from spreadsheet - Fix frontend color mappings: remove typo duplicates, rename Silk prefixed colors to match catalog - Add Translucent Teal, Phantom Blue, Mystic Magenta mappings - Remove non-existent ABS GF, TPU 95A HF entries - Update tests for corrected color names
This commit is contained in:
10
CLAUDE.md
10
CLAUDE.md
@@ -48,14 +48,14 @@ scripts/deploy-frontend.sh # Manual frontend deploy to S3/CloudFront
|
|||||||
|
|
||||||
### Frontend (Next.js App Router)
|
### Frontend (Next.js App Router)
|
||||||
- `/app/page.tsx` — Public filament inventory table (home page)
|
- `/app/page.tsx` — Public filament inventory table (home page)
|
||||||
- `/app/upadaj/` — Admin panel: login, `/dashboard` (filament CRUD), `/colors` (color management), `/requests` (customer color requests)
|
- `/app/upadaj/` — Admin panel: login, `/dashboard` (filament CRUD), `/colors` (color management), `/customers` (customer management), `/sales` (sales recording), `/requests` (customer color requests), `/analytics` (revenue/inventory dashboards)
|
||||||
- `/src/services/api.ts` — Axios instance with auth interceptors (auto token injection, 401/403 redirect)
|
- `/src/services/api.ts` — Axios instance with auth interceptors (auto token injection, 401/403 redirect)
|
||||||
- `/src/data/bambuLabColors.ts` — Primary color-to-hex mapping with gradient support (used by `ColorCell` component)
|
- `/src/data/bambuLabColors.ts` — Primary color-to-hex mapping with gradient support (used by `ColorCell` component)
|
||||||
- `/src/data/bambuLabColorsComplete.ts` — Extended color database grouped by finish type (used by filters)
|
- `/src/data/bambuLabColorsComplete.ts` — Extended color database grouped by finish type (used by filters)
|
||||||
|
|
||||||
### API (`/api/server.js`)
|
### API (`/api/server.js`)
|
||||||
Single-file Express server running on EC2 (port 80). All routes inline.
|
Single-file Express server running on EC2 (port 80). All routes inline.
|
||||||
- Endpoints: `/api/login`, `/api/filaments`, `/api/colors`, `/api/sale/bulk`, `/api/color-requests`
|
- Endpoints: `/api/login`, `/api/filaments`, `/api/colors`, `/api/customers`, `/api/sales`, `/api/color-requests`, `/api/analytics/*`
|
||||||
- Auth: JWT tokens with 24h expiry, single admin user (password from `ADMIN_PASSWORD` env var)
|
- Auth: JWT tokens with 24h expiry, single admin user (password from `ADMIN_PASSWORD` env var)
|
||||||
|
|
||||||
### Database (PostgreSQL on RDS)
|
### Database (PostgreSQL on RDS)
|
||||||
@@ -64,13 +64,15 @@ Key schemas and constraints:
|
|||||||
```
|
```
|
||||||
filaments: id, tip (material), finish, boja (color), refill, spulna, kolicina, cena, sale_*
|
filaments: id, tip (material), finish, boja (color), refill, spulna, kolicina, cena, sale_*
|
||||||
colors: id, name, hex, cena_refill (default 3499), cena_spulna (default 3999)
|
colors: id, name, hex, cena_refill (default 3499), cena_spulna (default 3999)
|
||||||
|
customers: id, name, phone (unique), city, notes, created_at
|
||||||
|
sales: id, customer_id (FK→customers), total_amount, notes, created_at + sale_items join table
|
||||||
color_requests: id, color_name, message, contact_name, contact_phone, status
|
color_requests: id, color_name, message, contact_name, contact_phone, status
|
||||||
```
|
```
|
||||||
|
|
||||||
**Critical constraints:**
|
**Critical constraints:**
|
||||||
- `filaments.boja` → FK to `colors.name` (ON UPDATE CASCADE) — colors must exist before filaments reference them
|
- `filaments.boja` → FK to `colors.name` (ON UPDATE CASCADE) — colors must exist before filaments reference them
|
||||||
- `kolicina = refill + spulna` — enforced by check constraint
|
- `kolicina = refill + spulna` — enforced by check constraint
|
||||||
- Migrations in `/database/migrations/` with sequential numbering (currently up to `020_`)
|
- Migrations in `/database/migrations/` with sequential numbering (currently up to `023_`)
|
||||||
|
|
||||||
## Key Patterns
|
## Key Patterns
|
||||||
|
|
||||||
@@ -86,7 +88,7 @@ color_requests: id, color_name, message, contact_name, contact_phone, status
|
|||||||
3. Optionally add to `src/data/bambuLabColorsComplete.ts` finish groups
|
3. Optionally add to `src/data/bambuLabColorsComplete.ts` finish groups
|
||||||
|
|
||||||
### API Communication
|
### API Communication
|
||||||
- Service modules in `src/services/api.ts`: `authService`, `colorService`, `filamentService`, `colorRequestService`
|
- Service modules in `src/services/api.ts`: `authService`, `colorService`, `filamentService`, `colorRequestService`, `customerService`, `saleService`, `analyticsService`
|
||||||
- Auth token stored in localStorage with 24h expiry
|
- Auth token stored in localStorage with 24h expiry
|
||||||
- Cache busting on filament fetches via timestamp query param
|
- Cache busting on filament fetches via timestamp query param
|
||||||
|
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ describe('Bambu Lab Colors Data', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have Unknown fallback color', () => {
|
it('should return fallback for unknown colors', () => {
|
||||||
expect(bambuLabColors).toHaveProperty('Unknown');
|
const result = getFilamentColor('NonExistentColor');
|
||||||
expect(bambuLabColors.Unknown.hex).toBe('#CCCCCC');
|
expect(result.hex).toBe('#CCCCCC');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ describe('Bambu Lab Colors Complete Data', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should have silk colors', () => {
|
it('should have silk colors', () => {
|
||||||
expect(bambuLabColors).toHaveProperty('Silk Aurora Purple');
|
expect(bambuLabColors).toHaveProperty('Aurora Purple');
|
||||||
expect(bambuLabColors).toHaveProperty('Silk Phantom Blue');
|
expect(bambuLabColors).toHaveProperty('Phantom Blue');
|
||||||
expect(bambuLabColors).toHaveProperty('Silk Mystic Magenta');
|
expect(bambuLabColors).toHaveProperty('Mystic Magenta');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have valid hex colors', () => {
|
it('should have valid hex colors', () => {
|
||||||
|
|||||||
100
database/migrations/023_cleanup_fake_colors_add_missing.sql
Normal file
100
database/migrations/023_cleanup_fake_colors_add_missing.sql
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
-- Migration 023: Clean up fake colors and add missing real Bambu Lab colors
|
||||||
|
-- Source of truth: bambu_lab_filaments.numbers spreadsheet
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
-- 1. Rename typo: IronGray Metallic → Iron Gray Metallic (FK cascades to filaments)
|
||||||
|
UPDATE colors SET name = 'Iron Gray Metallic' WHERE name = 'IronGray Metallic';
|
||||||
|
|
||||||
|
-- 2. Delete 67 fake colors not used by any filament
|
||||||
|
DELETE FROM colors WHERE name IN (
|
||||||
|
'Coton Candy Cloud',
|
||||||
|
'Glow in the Dark Blue',
|
||||||
|
'Glow in the Dark Green',
|
||||||
|
'Grey',
|
||||||
|
'Indingo Purple',
|
||||||
|
'Ivory',
|
||||||
|
'Ivory White',
|
||||||
|
'Light Blue',
|
||||||
|
'Light Green',
|
||||||
|
'Matte Black',
|
||||||
|
'Matte Blue',
|
||||||
|
'Matte Brown',
|
||||||
|
'Matte Coral',
|
||||||
|
'Matte Green',
|
||||||
|
'Matte Grey',
|
||||||
|
'Matte Lime',
|
||||||
|
'Matte Mint',
|
||||||
|
'Matte Navy',
|
||||||
|
'Matte Orange',
|
||||||
|
'Matte Pink',
|
||||||
|
'Matte Purple',
|
||||||
|
'Matte White',
|
||||||
|
'Matte Yellow',
|
||||||
|
'Metal Bronze',
|
||||||
|
'Metal Copper',
|
||||||
|
'Metal Gold',
|
||||||
|
'Metal Grey',
|
||||||
|
'Metal Silver',
|
||||||
|
'Mint Green',
|
||||||
|
'Natural',
|
||||||
|
'Navy Blue',
|
||||||
|
'Nebulane',
|
||||||
|
'Silk Black',
|
||||||
|
'Silk Blue',
|
||||||
|
'Silk Bronze',
|
||||||
|
'Silk Copper',
|
||||||
|
'Silk Emerald',
|
||||||
|
'Silk Gold',
|
||||||
|
'Silk Green',
|
||||||
|
'Silk Jade',
|
||||||
|
'Silk Orange',
|
||||||
|
'Silk Pearl',
|
||||||
|
'Silk Pink',
|
||||||
|
'Silk Purple',
|
||||||
|
'Silk Red',
|
||||||
|
'Silk Rose Gold',
|
||||||
|
'Silk Ruby',
|
||||||
|
'Silk Sapphire',
|
||||||
|
'Silk Silver',
|
||||||
|
'Silk White',
|
||||||
|
'Sky Blue',
|
||||||
|
'Sparkle Blue',
|
||||||
|
'Sparkle Gold',
|
||||||
|
'Sparkle Green',
|
||||||
|
'Sparkle Purple',
|
||||||
|
'Sparkle Red',
|
||||||
|
'Sparkle Silver',
|
||||||
|
'Support G',
|
||||||
|
'Support White',
|
||||||
|
'Translucent Tea',
|
||||||
|
'Transparent Blue',
|
||||||
|
'Transparent Green',
|
||||||
|
'Transparent Orange',
|
||||||
|
'Transparent Purple',
|
||||||
|
'Transparent Red',
|
||||||
|
'Transparent Yellow',
|
||||||
|
'Violet'
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 3. Add 17 missing real Bambu Lab colors from spreadsheet
|
||||||
|
INSERT INTO colors (name, hex) VALUES
|
||||||
|
('Aurora Purple', '#285BB7'),
|
||||||
|
('Candy Green', '#408619'),
|
||||||
|
('Candy Red', '#BB3A2E'),
|
||||||
|
('Crystal Blue', '#5BC0EB'),
|
||||||
|
('Flesh', '#E8C4A2'),
|
||||||
|
('Forest Green', '#415520'),
|
||||||
|
('Grape Jelly', '#6B2D75'),
|
||||||
|
('Lake Blue', '#4672E4'),
|
||||||
|
('Lime', '#C5ED48'),
|
||||||
|
('Mystic Magenta', '#720062'),
|
||||||
|
('Nebulae', '#424379'),
|
||||||
|
('Neon Green', '#ABFF1E'),
|
||||||
|
('Phantom Blue', '#00629B'),
|
||||||
|
('Quicksilver', '#A6A9AA'),
|
||||||
|
('Rose Gold', '#B29593'),
|
||||||
|
('Translucent Teal', '#008080')
|
||||||
|
ON CONFLICT (name) DO NOTHING;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -115,9 +115,9 @@ export const BAMBU_LAB_CATALOG: BambuLabCatalog = {
|
|||||||
},
|
},
|
||||||
'Silk Multi-Color': {
|
'Silk Multi-Color': {
|
||||||
colors: [
|
colors: [
|
||||||
{ name: 'Silk Aurora Purple', refill: false, spool: true },
|
{ name: 'Aurora Purple', refill: false, spool: true },
|
||||||
{ name: 'Silk Phantom Blue', refill: false, spool: true },
|
{ name: 'Phantom Blue', refill: false, spool: true },
|
||||||
{ name: 'Silk Mystic Magenta', refill: false, spool: true },
|
{ name: 'Mystic Magenta', refill: false, spool: true },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Metal: {
|
Metal: {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export const bambuLabColors: Record<string, ColorMapping> = {
|
|||||||
'Apple Green': { hex: '#C6E188' },
|
'Apple Green': { hex: '#C6E188' },
|
||||||
'Arctic Whisper': { hex: '#ECF7F8' },
|
'Arctic Whisper': { hex: '#ECF7F8' },
|
||||||
'Ash Grey': { hex: '#9B9EA0' },
|
'Ash Grey': { hex: '#9B9EA0' },
|
||||||
'Aurora Purple': { hex: '#285BB7' },
|
'Aurora Purple': { hex: ['#7F3696', '#006EC9'], isGradient: true },
|
||||||
'Azure': { hex: '#489FDF' },
|
'Azure': { hex: '#489FDF' },
|
||||||
'Baby Blue': { hex: '#AEC3ED' },
|
'Baby Blue': { hex: '#AEC3ED' },
|
||||||
'Bambu Green': { hex: '#00AE42' },
|
'Bambu Green': { hex: '#00AE42' },
|
||||||
@@ -73,8 +73,6 @@ export const bambuLabColors: Record<string, ColorMapping> = {
|
|||||||
'Iridium Gold Metallic': { hex: '#B39B84' },
|
'Iridium Gold Metallic': { hex: '#B39B84' },
|
||||||
'Iris Purple': { hex: '#69398E' },
|
'Iris Purple': { hex: '#69398E' },
|
||||||
'Iron Gray Metallic': { hex: '#6B6C6F' },
|
'Iron Gray Metallic': { hex: '#6B6C6F' },
|
||||||
'IronGray Metallic': { hex: '#6B6C6F' },
|
|
||||||
'Ivory White': { hex: '#FFFFFF' },
|
|
||||||
'Jade White': { hex: '#FFFFFF' },
|
'Jade White': { hex: '#FFFFFF' },
|
||||||
'Jeans Blue': { hex: '#6E88BC' },
|
'Jeans Blue': { hex: '#6E88BC' },
|
||||||
'Lake Blue': { hex: '#4672E4' },
|
'Lake Blue': { hex: '#4672E4' },
|
||||||
@@ -103,7 +101,6 @@ export const bambuLabColors: Record<string, ColorMapping> = {
|
|||||||
'Nardo Gray': { hex: '#747474' },
|
'Nardo Gray': { hex: '#747474' },
|
||||||
'Navy Blue': { hex: '#0C2340' },
|
'Navy Blue': { hex: '#0C2340' },
|
||||||
'Nebulae': { hex: '#424379' },
|
'Nebulae': { hex: '#424379' },
|
||||||
'Nebulane': { hex: '#424379' },
|
|
||||||
'Neon City': { hex: '#0047BB' },
|
'Neon City': { hex: '#0047BB' },
|
||||||
'Neon Green': { hex: '#ABFF1E' },
|
'Neon Green': { hex: '#ABFF1E' },
|
||||||
'Neon Orange': { hex: '#F68A1B' },
|
'Neon Orange': { hex: '#F68A1B' },
|
||||||
@@ -147,8 +144,6 @@ export const bambuLabColors: Record<string, ColorMapping> = {
|
|||||||
'Yellow': { hex: '#F4EE2A' },
|
'Yellow': { hex: '#F4EE2A' },
|
||||||
|
|
||||||
// ABS Colors
|
// ABS Colors
|
||||||
'ABS GF Yellow': { hex: '#FDD835' },
|
|
||||||
'ABS GF Orange': { hex: '#F48438' },
|
|
||||||
'ABS Azure': { hex: '#489FDF' },
|
'ABS Azure': { hex: '#489FDF' },
|
||||||
'ABS Olive': { hex: '#748C45' },
|
'ABS Olive': { hex: '#748C45' },
|
||||||
'ABS Blue': { hex: '#0A2989' },
|
'ABS Blue': { hex: '#0A2989' },
|
||||||
@@ -169,7 +164,7 @@ export const bambuLabColors: Record<string, ColorMapping> = {
|
|||||||
'Translucent Olive': { hex: '#A4B885' },
|
'Translucent Olive': { hex: '#A4B885' },
|
||||||
'Translucent Pink': { hex: '#F9B8D0' },
|
'Translucent Pink': { hex: '#F9B8D0' },
|
||||||
'Translucent Light Blue': { hex: '#A8D8F0' },
|
'Translucent Light Blue': { hex: '#A8D8F0' },
|
||||||
'Translucent Tea': { hex: '#D9C7A8' },
|
'Translucent Teal': { hex: '#008080' },
|
||||||
|
|
||||||
// PLA Matte Colors
|
// PLA Matte Colors
|
||||||
'Matte Ivory White': { hex: '#FFFFF0' },
|
'Matte Ivory White': { hex: '#FFFFF0' },
|
||||||
@@ -199,19 +194,14 @@ export const bambuLabColors: Record<string, ColorMapping> = {
|
|||||||
'Matte Terracotta': { hex: '#A25A37' },
|
'Matte Terracotta': { hex: '#A25A37' },
|
||||||
|
|
||||||
// PLA Silk Multi-Color
|
// PLA Silk Multi-Color
|
||||||
'Silk Aurora Purple': { hex: ['#7F3696', '#006EC9'], isGradient: true },
|
'Phantom Blue': { hex: ['#00629B', '#000000'], isGradient: true },
|
||||||
'Silk Phantom Blue': { hex: ['#00629B', '#000000'], isGradient: true },
|
'Mystic Magenta': { hex: ['#720062', '#3A913F'], isGradient: true },
|
||||||
'Silk Mystic Magenta': { hex: ['#720062', '#3A913F'], isGradient: true },
|
|
||||||
|
|
||||||
// TPU Colors
|
// TPU Colors
|
||||||
'Flesh': { hex: '#E8C4A2' },
|
'Flesh': { hex: '#E8C4A2' },
|
||||||
'Grape Jelly': { hex: '#6B2D75' },
|
'Grape Jelly': { hex: '#6B2D75' },
|
||||||
'Crystal Blue': { hex: '#5BC0EB' },
|
'Crystal Blue': { hex: '#5BC0EB' },
|
||||||
'Quicksilver': { hex: '#A6A9AA' },
|
'Quicksilver': { hex: '#A6A9AA' }
|
||||||
'TPU 95A HF Yellow': { hex: '#F3E600' },
|
|
||||||
|
|
||||||
// Default fallback
|
|
||||||
'Unknown': { hex: '#CCCCCC' }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getFilamentColor(colorName: string): ColorMapping {
|
export function getFilamentColor(colorName: string): ColorMapping {
|
||||||
@@ -240,7 +230,7 @@ export function getFilamentColor(colorName: string): ColorMapping {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return default unknown color
|
// Return default unknown color
|
||||||
return bambuLabColors['Unknown'];
|
return { hex: '#CCCCCC' };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getColorStyle(colorMapping: ColorMapping): React.CSSProperties {
|
export function getColorStyle(colorMapping: ColorMapping): React.CSSProperties {
|
||||||
|
|||||||
@@ -100,9 +100,9 @@ export const bambuLabColors: Record<string, string> = {
|
|||||||
"Baby Blue": "#AEC3ED",
|
"Baby Blue": "#AEC3ED",
|
||||||
|
|
||||||
// PLA Silk Multi-Color
|
// PLA Silk Multi-Color
|
||||||
"Silk Aurora Purple": "#7F3696",
|
"Aurora Purple": "#7F3696",
|
||||||
"Silk Phantom Blue": "#00629B",
|
"Phantom Blue": "#00629B",
|
||||||
"Silk Mystic Magenta": "#720062",
|
"Mystic Magenta": "#720062",
|
||||||
|
|
||||||
// PLA Metal
|
// PLA Metal
|
||||||
"Iron Gray Metallic": "#6B6C6F",
|
"Iron Gray Metallic": "#6B6C6F",
|
||||||
@@ -162,7 +162,7 @@ export const bambuLabColors: Record<string, string> = {
|
|||||||
"Translucent Olive": "#A4B885",
|
"Translucent Olive": "#A4B885",
|
||||||
"Translucent Pink": "#F9B8D0",
|
"Translucent Pink": "#F9B8D0",
|
||||||
"Translucent Light Blue": "#A8D8F0",
|
"Translucent Light Blue": "#A8D8F0",
|
||||||
"Translucent Tea": "#D9C7A8",
|
"Translucent Teal": "#008080",
|
||||||
|
|
||||||
// PETG CF
|
// PETG CF
|
||||||
"Brick Red": "#9F332A",
|
"Brick Red": "#9F332A",
|
||||||
|
|||||||
Reference in New Issue
Block a user