Saltar al contenido principal

Modules System

The modules system controls feature enablement across the FlowPOS platform. It consists of three backend modules working together:

ModuleTablePurpose
modulesmoduleGlobal catalog of feature modules (POS, Inventory, Billing, etc.)
business-modulesbusiness_moduleMany-to-many enablement of modules per business
formsformNavigation page definitions linked to modules

Architecture

All three modules follow hexagonal architecture:

domain/          → Repository port interface (IModulesRepository)
application/ → Service with business logic
infrastructure/ → Kysely repository adapter
interfaces/ → Controller, DTOs, query objects

Dependencies are injected via Symbol tokens (MODULES_REPOSITORY, BUSINESS_MODULES_REPOSITORY, FORMS_REPOSITORY).

Domain Concepts

Module

A module represents a high-level feature area. There are 18 system-seeded modules:

ModuleUUID
Settings8da5d77c-2e3b-4c85-b225-debffa5138d8
POSe1db4d48-3b04-40bc-8451-d84fdd6293b2
Inventory5a47f719-6d63-4edc-b553-b90d4a3cea19
Goods & Servicesa43a7bea-f4b6-461c-b6e0-7e349eb048ed
Billing7a45fa4e-dfe3-4e49-b90f-86bc0ff28582
Accounts Receivable4ed0bdeb-cf1d-460f-a38e-35b2c4a3f699
Accounts Payable06560d1a-9b49-49cb-8990-db5a90685f80
Purchasec4561699-ace1-415b-b1ca-81b19f6dfc20
Productiond3e38289-3da9-428b-a2f7-516c9408c7f0
Customersb84f3caa-ec30-4378-9a02-8763c7221f7b
Reports011d26b6-1266-40e8-bca3-50ce71871f77
Payroll8f3f7a0e-1f9b-4821-af10-15462a31f2e8
Admina0e48832-47d6-465d-9657-675650c332c0
Systemf6fac323-e52c-4628-9200-20bfe28ee489
Service Bookings7ffde23e-0688-4b2b-9cde-132cb531280a
Communication2b69cc58-57ac-4e1b-9488-bc660f18e4a9
Restaurant6c483495-c30a-42b5-8522-ad4e440cb9fa
Data Importa1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d

Modules can be system-wide (businessId = null) or business-specific (businessId set).

Business Module

A business_module record links a business to a module, controlling whether that feature is enabled. When a new business is created, the OnCreateBusinessEvent listener automatically seeds 17 default associations.

Form

A form represents a navigation entry (route/page) in the PWA, linked to a module via moduleId. Forms define the dynamic menu structure.

Key Flows

Business Creation → Module Enablement

Business Created
→ OnCreateBusinessEvent emitted
→ BusinessModulesService.handleBusinessCreateEvent()
→ 17 default business_module records created

Module → Form → Navigation

Module (feature area)
→ Forms (pages within module)
→ PWA navigation menu
→ Metabase dashboards (optional)

Soft Delete

Deleting a module performs a soft delete (isActive = false) on both the module record and all related business_module records.

API Endpoints

Modules (/modules)

MethodPathDescription
POST/modulesCreate a feature module
GET/modulesList all modules
GET/modules/:idGet module by ID
GET/modules/business/:businessIdList modules owned by a business
GET/modules/with-relation/:businessIdList all modules with business enablement status
PATCH/modules/:idUpdate a module
DELETE/modules/:id?businessId=Soft-delete a module

Business Modules (/business-modules)

MethodPathDescription
POST/business-modulesCreate a business-module association
GET/business-modulesList with pagination (filter by businessId)
GET/business-modules/:idGet by ID
PATCH/business-modules/:idUpdate association
PATCH/business-modules/disable-module/:id?businessId=Soft-disable a module for a business
DELETE/business-modules/:idHard-delete association (204)

Forms (/forms)

MethodPathDescription
POST/formsCreate a navigation form
GET/formsList with pagination, search, sorting
GET/forms/:idGet by ID
PATCH/forms/:idUpdate a form
DELETE/forms/:idDelete a form

Adding New Modules

When adding a new system module:

  1. Add the UUID to packages/backend/database/src/seeds/data/global/module.data.ts
  2. Create a migration to insert the module record (use onConflict().doNothing())
  3. Create a migration for associated forms
  4. Optionally backfill business_module for existing businesses
  5. Add the module to defaultBusinessModules in BusinessModulesService.handleBusinessCreateEvent()

Design Decisions

  • Soft delete over hard delete: Modules use isActive = false to preserve referential integrity with forms, dashboards, and business associations.
  • Event-driven module seeding: Decouples business creation from module setup via OnCreateBusinessEvent.
  • System vs. business modules: System modules (isSystem = true, businessId = null) are platform-wide; business modules are custom per-business features.
  • with-relation endpoint: Returns all modules with a LEFT JOIN to business_module, enabling the admin UI to show both enabled and available modules in one request.