System Module Registry
Overview
system_module is the master table that declares which modules the platform is made of —
campaign, rich-menu, form-builder, audiences, and so on. Every mechanism related to
permissions or feature toggling refers back to this table:
system_role_modulereferencesmodule_idto express role-based permissionsorganization_modulereferencesmodule_idto override permissions per organizationModuleGateusessystem_module.nameas the key for checking whether a module is enabled
Because this is platform-level data, every endpoint in the module enforces SuperAdminGuard.
Business Flow
- A platform operator (
roleId = 1) opens the module management screen in cms-web. GET /api/system-modulelists all modules, with the soft-delete filterdeleted_date IS NULLapplied automatically.GET /api/system-module/list-all-objectreturns an{id: name}shape. The user module calls thisFindAllObjectfunction directly to translatemodule_idvalues into module names in the permission response.- New modules are added with
POST /api/system-module. The name must match exactly whatModuleGate(d, "module-name")uses, otherwise the gate will not find it. - Updates and removals go through
PUT /api/system-module/:idandDELETE /api/system-module/:id(soft delete). - Additions and edits surface in the dropdown on the per-organization module settings screen, where platform admins enable or disable modules for each customer.
Parity note: the SystemModule entity genuinely has a @DeleteDateColumn, so GORM appends
deleted_date IS NULL automatically via gorm.DeletedAt. However, update() and softDelete()
must use Unscoped(), because TypeORM did not apply the filter in those two cases.
Key Files & Functions
The code lives in internal/modules/systemmodule/, consisting of controller.go, service.go,
and dto.go.
| Method | Route | Handler | Policy (metadata) |
|---|---|---|---|
| GET | /api/system-module | h.findAll | readAll system_module |
| GET | /api/system-module/list-all-object | h.findAllObject | readAll system_module |
| GET | /api/system-module/:id | h.findOne | read system_module |
| POST | /api/system-module | h.create | create system_module |
| PUT | /api/system-module/:id | h.update | update system_module |
| DELETE | /api/system-module/:id | h.delete | delete system_module |
Every route carries auth.SuperAdmin() as middleware, registered on
authed.Group("/system-module").
The function other modules call is systemmodule.Service.FindAllObject(ctx), which returns a map
from id to name.
Connections to Other Services
- Permissions —
auth.SuperAdmin()on every route:roleIdmust equal 1, otherwise the request is rejected with 403Forbidden resource. - Tables —
system_module, referenced fromsystem_role_moduleandorganization_module - Consumers — CMS user management (through
FindPermissionByUserID), per-organization module settings, andModuleGate, which keys offname. - Note — the menu-builder module also uses
PolicyModuleSystemModuleas its policy metadata, carried over from the original TypeScript implementation.