Module Config Reference
The module config is a PHP array (or JSON object) that fully describes a single module to be generated. It is the primary input for all generator classes.
Top-Level Keys
{
"id": "string (UUID v5 derived from module name)",
"module_name": "Products",
"module_type": "Custom",
"table_name": "products",
"id_type": "uuid | bigint",
"module_group_name": "Core | Custom | null",
"version": "1.0.0",
"columns": [],
"indexes": [],
"morphs": [],
"features": {},
"delegations": {},
"actions": {},
"processors": [],
"seeder": [],
"menu_config": {},
"constants": {}
}| Key | Type | Required | Description |
|---|---|---|---|
id | string | No | UUID v5 identifier. Auto-set by introspection. |
module_name | string | Yes | StudlyCase singular name, e.g. Products. |
module_type | string | No | "Custom" or "Core". Affects namespace/path. Default "Custom". |
table_name | string | Yes | Exact DB table name, e.g. products. |
id_type | string | No | "uuid" (default) or "bigint". Affects model and migration. |
module_group_name | string|null | No | Sub-group label. Used in some menu groupings. |
version | string | No | Semantic version. Default "1.0.0". |
columns | array | Yes | Column definitions — see columns.md. |
indexes | array | No | Additional composite indexes beyond single-column ones. |
morphs | array | No | Polymorphic relationship declarations — see below. A genuine flat array (unlike delegations/actions) — auto-detected by introspection, rarely hand-authored. |
features | object | Yes | Backend + frontend + mobile feature config — see features-config.md. |
delegations | object | No | Related-module tab/modal panels, keyed by delegation key — see delegations.md. |
actions | object | No | Custom action buttons and services, keyed by action key — see actions.md. |
processors | array | No | Pipeline hooks (before/after save/delete) — see processors.md. |
seeder | array | No | Seed rows. Each entry is a flat object matching column names. |
menu_config | object|null | No | Navigation placement — see below. |
constants | object | No | Flat { CONST_NAME: value } map — see below. |
List filters.
features.backend.list.filterFieldscan be left empty — it auto-derives type-aware filters fromfilterableFields, andid/uuid/created_atare always added as default filters regardless of config. See features-config.md § Filter fields for the full behavior.
morphs Array
Declare polymorphic relationships on this table. Auto-detected by schema introspection (a {prefix}_type/{prefix}_id column pair) — name/type_column/id_column are populated for you; only targets is ever hand-authored.
"morphs": [
{
"name": "commentable",
"type_column": "commentable_type",
"id_column": "commentable_id",
"targets": [
{ "alias": "post", "model": "App\\Project\\Modules\\Custom\\Posts\\PostsModel", "module": "Posts", "label": "Post" }
]
}
]The generator uses this to emit a morphTo() relationship method and correct migration lines ($table->morphs('commentable') on regeneration) — always, whether or not targets is set. morphMany()/morphOne() (the inverse, on the target side) is not emitted — that stays a manual add if you want e.g. $post->comments to work.
targets (optional, never auto-guessed) drives two things once populated: a morph-select create/edit field (type dropdown + API-backed record picker, replacing the fallback plain text/number input pair) and a Relation::morphMap() registration on this module's own generated boot() method. Each entry requires alias/model/module/label; option_label is optional (which field to show in the record picker, defaults to name). The same alias registered for two different model values across the whole project is a hard-fail at generation time — see the morphs example page for the full config shape and behavior.
menu_config Object
Controls where this module appears in the navigation sidebar.
"menu_config": {
"enabled": true,
"section": "main",
"section_label": "Main Menu",
"icon": "Package",
"permission": "Products.list",
"nested": false,
"items": [
{
"title": "All Products",
"url": "/products/list",
"icon": "List",
"permission": "Products.list",
"children": []
}
]
}| Key | Type | Default | Description |
|---|---|---|---|
enabled | boolean | true | Set false to hide from nav entirely. |
section | string | "main" | ID of the nav section to place this module in. |
section_label | string | — | Optional override for the section heading text. |
icon | string | "File" | Lucide icon name. |
permission | string | "{Module}.list" | Guard permission for this nav item. |
nested | boolean | false | If true, renders a parent item with List and Create children. |
items | array | — | Fully custom nav items. Overrides the auto-generated entry. |
constants Object
Corrected 2026-08-02
constants is a flat key → value map, not an array of named groups. This page previously showed [{"name": "STATUS", "values": [...]}] — verified against ModelGenerator::generateConstants()'s actual source: foreach ($constants as $name => $value) { ... "public const {$name} = ...;" }.
Defines PHP public const values emitted directly on the generated model — used both by createSplash/editSplash features (field-level splash dropdowns) and, separately, by bulk_actions[].status_target (see features-config.md), which references a constant here by name to resolve the numeric status_id value to transition to.
"constants": {
"ACTIVE": 1,
"INACTIVE": 2,
"RECEIVED": 3
}Each key becomes public const {KEY} = {VALUE}; on the model — a numeric value is emitted unquoted (public const ACTIVE = 1;), anything else is quoted as a PHP string (public const STATUS = 'draft';).
seeder Array
Simple array of row objects to seed the table. Keys must match column names.
"seeder": [
{ "name": "Electronics", "code": "ELEC", "color": "blue" },
{ "name": "Clothing", "code": "CLO", "color": "green" }
]indexes Array
Additional indexes beyond those auto-created from unique: true on columns.
"indexes": [
{ "columns": ["category_id", "status_id"], "unique": false }
]Complete Minimal Example
{
"module_name": "Products",
"module_type": "Custom",
"table_name": "products",
"id_type": "uuid",
"columns": [
{
"name": "name",
"type": "string",
"nullable": false,
"unique": false,
"featureSelections": {
"backend": { "create": true, "list": true, "view": true, "edit": true, "delete": false },
"frontend": { "create": true, "list": true, "view": true, "edit": true, "delete": false }
}
}
],
"features": {
"backend": {
"list": { "endpoint": { "method": "GET", "path": "/products", "permission": "Products.list" } },
"create": { "endpoint": { "method": "POST", "path": "/products", "permission": "Products.create" } },
"view": { "endpoint": { "method": "GET", "path": "/products/{uuid}", "permission": "Products.view" } },
"edit": { "endpoint": { "method": "PUT", "path": "/products/{uuid}", "permission": "Products.edit" } },
"delete": { "endpoint": { "method": "DELETE", "path": "/products/{uuid}", "permission": "Products.delete" } }
},
"frontend": {
"list": { "primaryField": "name", "fields": [] },
"create": { "fields": [] },
"view": { "titleData": "name", "fields": [] },
"edit": { "fields": [] },
"delete": { "fields": [] }
},
"mobile_app": { "enabled": false }
},
"menu_config": { "section": "main", "icon": "Package" }
}Corrected 2026-08-02
This page previously linked to examples/module-config-full.json, which does not exist in this repository. See Examples instead — a set of worked, task-oriented recipes, each pointing at a real config that was actually generated and verified end-to-end (not a static example file).