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:
26
packages/backend/src/routes/v1/modules.ts
Normal file
26
packages/backend/src/routes/v1/modules.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import type { FastifyPluginAsync } from 'fastify'
|
||||
import { ModuleService } from '../../services/module.service.js'
|
||||
|
||||
export const moduleRoutes: FastifyPluginAsync = async (app) => {
|
||||
app.get('/modules', { preHandler: [app.authenticate, app.requirePermission('settings.view')] }, async (_request, reply) => {
|
||||
const modules = await ModuleService.listAll(app.db)
|
||||
return reply.send({ data: modules })
|
||||
})
|
||||
|
||||
app.patch('/modules/:slug', { preHandler: [app.authenticate, app.requirePermission('settings.edit')] }, async (request, reply) => {
|
||||
const { slug } = request.params as { slug: string }
|
||||
const { enabled } = request.body as { enabled?: boolean }
|
||||
|
||||
if (typeof enabled !== 'boolean') {
|
||||
return reply.status(400).send({ error: { message: 'enabled (boolean) is required', statusCode: 400 } })
|
||||
}
|
||||
|
||||
try {
|
||||
const updated = await ModuleService.setEnabled(app.db, slug, enabled)
|
||||
if (!updated) return reply.status(404).send({ error: { message: 'Module not found', statusCode: 404 } })
|
||||
return reply.send(updated)
|
||||
} catch (err: any) {
|
||||
return reply.status(400).send({ error: { message: err.message, statusCode: 400 } })
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user