feat: unified Catalog page with Location→Category→Subcategory→Product tree

- New /catalog page with tree view: Location (🌍) → Category (📂) → Subcategory (📁) → Product
- Add/delete locations, categories, subcategories, products from one page
- JS-powered subcategory dropdown filtered by category
- Sticky sidebar with Add Location/Category/Product forms
- Responsive grid layout (tree + forms side by side, stacks on mobile)
- Navigation simplified: Catalog replaces separate Locations/Categories/Products
- Old routes still accessible for backward compatibility
- Subcategories table migration (006_subcategories.js)
- subcategory_id column added to products table
- Seed data includes subcategories (VPN, Accounts, Hardware, etc.)
This commit is contained in:
NW
2026-06-22 21:12:05 +01:00
parent 2012435370
commit c7bf3f132c
17 changed files with 693 additions and 69 deletions

View File

@@ -0,0 +1,23 @@
import logger from '../utils/logger.js';
export default async function migration006(db) {
await db.runAsync('BEGIN TRANSACTION');
await db.runAsync(`CREATE TABLE IF NOT EXISTS subcategories (
id INTEGER PRIMARY KEY AUTOINCREMENT,
category_id INTEGER NOT NULL,
name TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE CASCADE,
UNIQUE(category_id, name)
)`);
const cols = await db.allAsync('PRAGMA table_info(products)');
const hasSubcat = cols.some(c => c.name === 'subcategory_id');
if (!hasSubcat) {
await db.runAsync(`ALTER TABLE products ADD COLUMN subcategory_id INTEGER REFERENCES subcategories(id) ON DELETE SET NULL`);
}
await db.runAsync('COMMIT');
logger.info('Migration 006: subcategories table + products.subcategory_id column');
}

View File

@@ -3,7 +3,7 @@ import logger from '../utils/logger.js';
const ALLOWED_TABLES = new Set([
'users', 'crypto_wallets', 'transactions', 'products',
'purchases', 'locations', 'categories'
'purchases', 'locations', 'categories', 'subcategories'
]);
export const checkColumnExists = async (tableName, columnName) => {
@@ -40,6 +40,7 @@ export async function runMigrations() {
(await import('./003_add_indexes.js')).default,
(await import('./004_user_states.js')).default,
(await import('./005_audit_log.js')).default,
(await import('./006_subcategories.js')).default,
];
for (let i = currentVersion; i < migrations.length; i++) {