Add module management system for enabling/disabling features
Stores can enable/disable feature modules from Settings. When disabled, nav links are hidden and API routes return 403. Designed as the foundation for future license-based gating (licensed + enabled flags). Core modules (Accounts, Members, Users, Roles, Settings) are always on. - module_config table with slug, name, description, licensed, enabled - In-memory cache for fast per-request module checks - requireModule middleware wraps route groups in main.ts - Settings page Modules card with toggle switches - Sidebar hides nav links for disabled modules - Default modules seeded: inventory, pos, repairs, rentals, lessons, files, vault, email, reports
This commit is contained in:
24
packages/backend/src/db/migrations/0026_modules.sql
Normal file
24
packages/backend/src/db/migrations/0026_modules.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
-- Module configuration table for enabling/disabling feature modules
|
||||
|
||||
CREATE TABLE module_config (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
slug VARCHAR(50) NOT NULL UNIQUE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
licensed BOOLEAN NOT NULL DEFAULT true,
|
||||
enabled BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
-- Seed default modules
|
||||
INSERT INTO module_config (slug, name, description, licensed, enabled) VALUES
|
||||
('inventory', 'Inventory', 'Product catalog, stock tracking, and unit management', true, true),
|
||||
('pos', 'Point of Sale', 'Sales transactions, cash drawer, and receipts', true, true),
|
||||
('repairs', 'Repairs', 'Repair ticket management, batches, and service templates', true, true),
|
||||
('rentals', 'Rentals', 'Instrument rental agreements and billing', true, false),
|
||||
('lessons', 'Lessons', 'Lesson scheduling, instructor management, and billing', true, false),
|
||||
('files', 'Files', 'Shared file storage with folder organization', true, true),
|
||||
('vault', 'Vault', 'Encrypted password and secret manager', true, true),
|
||||
('email', 'Email', 'Email campaigns, templates, and sending', true, false),
|
||||
('reports', 'Reports', 'Business reports and data export', true, true);
|
||||
@@ -183,6 +183,13 @@
|
||||
"when": 1774850000000,
|
||||
"tag": "0025_vault",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 26,
|
||||
"version": "7",
|
||||
"when": 1774860000000,
|
||||
"tag": "0026_modules",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
14
packages/backend/src/db/schema/modules.ts
Normal file
14
packages/backend/src/db/schema/modules.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { pgTable, uuid, varchar, text, timestamp, boolean } from 'drizzle-orm/pg-core'
|
||||
|
||||
export const moduleConfig = pgTable('module_config', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
slug: varchar('slug', { length: 50 }).notNull().unique(),
|
||||
name: varchar('name', { length: 100 }).notNull(),
|
||||
description: text('description'),
|
||||
licensed: boolean('licensed').notNull().default(true),
|
||||
enabled: boolean('enabled').notNull().default(false),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
|
||||
})
|
||||
|
||||
export type ModuleConfig = typeof moduleConfig.$inferSelect
|
||||
Reference in New Issue
Block a user