Factorizer/Cluster ERP WikiCluster ERP Türkçe
Home / Web app

How-to guide

Add a screen with metadata

Add a list, form, and record card for an entity to a module app by declaring EntityMeta and a sidebar section, with no web app code.

This guide adds a new entity screen to an existing module app. You declare the entity in the module's metadata and add one sidebar section; the web app then shows a tab with a list, a create form, and a record card without any change in webapp/. Background is on metadata rendering. Writing the backend routes for the entity is covered by write a backend module.

Prerequisites

  • The module exists and is loaded by the module registry; see module lifecycle.
  • The entity has HTTP routes for list, get, create, update, and delete under the module's prefix /api/v1/<module> (src/cluster_erp/core/module_base.py:37-38).
  • The module has an app in the app catalogue with screen: "module", so it opens as a module app (webapp/js/home.js:2429). The catalogue is src/cluster_erp/modules/app_store/catalog.json.

Steps

  1. Declare an EntityMeta for the entity in the module's metadata.py. Give labels in English and Turkish, the entity_type, and the endpoint paths relative to the module prefix. Source: src/cluster_erp/core/metadata.py:553-649.

From src/cluster_erp/modules/currencies/metadata.py:302-313:

python PAYMENT_TERM_META = EntityMeta( label={"en": "Payment Term", "tr": "Ödeme Koşulu"}, label_plural={"en": "Payment Terms", "tr": "Ödeme Koşulları"}, entity_type="payment_term", is_settings_entity=True, endpoints={ "list": EndpointMeta(method="GET", path="/payment-terms/"), "create": EndpointMeta(method="POST", path="/payment-terms/"), "get": EndpointMeta(method="GET", path="/payment-terms/{id}"), "update": EndpointMeta(method="PUT", path="/payment-terms/{id}"), "delete": EndpointMeta(method="DELETE", path="/payment-terms/{id}"), },

  1. Add a list_view with columns and filters. Set search_enabled=True if the list endpoint accepts search; the list then shows a search field and the entity becomes searchable in the command palette. Source: webapp/js/gen-list.js:582-597, webapp/js/home.js:1241-1243.

  2. Add a form with field groups. Use field_type="decimal" for money so the value travels as a string. Source: webapp/js/gen-form.js:503-506, money and Decimal.

From src/cluster_erp/modules/currencies/metadata.py:365-373:

python FieldMeta( key="code", label={"en": "Code", "tr": "Kod"}, field_type="string", required=True, max_length=20, weight="hero", immutable_on_edit=True, ),

  1. If the record needs a card with several sections, add a detail_view with tabs. Without one, a row opens a read-only record card built from the form. Source: webapp/js/gen-list.js:816-844.

  2. Register the entity in ModuleMeta.entities and add a sidebar section with view_type="list" that names the entity key. Source: webapp/js/module-app.js:115-116.

From src/cluster_erp/modules/currencies/module.py:132-141:

python SidebarSectionMeta( key="payment_term_list", label={ "en": "Payment Terms", "tr": "Ödeme Koşulları", }, view_type="list", icon="payments", entity="payment_term", ),

  1. If the screen needs a specific permission beyond the entity's own codes, set required_permission on the section. Source: webapp/js/module-app.js:106-108.

  2. Restart the server. The metadata document is built once per process, and permission codes for each entity are seeded from metadata at start-up. Source: src/cluster_erp/server/app.py:1530-1543 and src/cluster_erp/server/app.py:634-858 at commit 92f8051.

  3. Grant the new <entity_type>.read, .create, .update, and .delete codes to the roles that need them. The system admin role receives every code automatically. See roles and permissions.

Verify the result

  • Open the module app. A new tab with the section label appears when the module has more than one tab (webapp/js/module-app.js:148-168).
  • The tab shows Add New (common.add) for a user with <entity_type>.create, and the list rows for a user with read access (webapp/js/gen-list.js:396-406, webapp/js/gen-list.js:702-711).
  • A row tap opens the card; Edit (common.edit) switches to the form (webapp/js/gen-form.js:2318-2346).
  • The Turkish label shows when the language is Turkish (webapp/js/meta.js:284-288).

Troubleshooting

Symptom Cause in code Fix
The server does not start after the change EntityMeta checks that detail form tabs cover every form group and raises ValueError at import (src/cluster_erp/core/metadata.py:617-649) Make the detail form tabs list every non-create_only group
The server does not start and names a sub-entity tab A sub_entity_table tab points at an entity without columns (src/cluster_erp/server/app.py:547-589) Give the child entity a list_view or sub_table
The tab is missing The section has hidden_from_bar, or the user lacks required_permission (webapp/js/module-app.js:105-108) Remove the flag or grant the permission
The tab shows No results found The section's entity does not match a key in ModuleMeta.entities (webapp/js/gen-list.js:358-362) Use the same key in both places
Add New is missing No create endpoint, or the user lacks <entity_type>.create (webapp/js/gen-list.js:396) Declare the endpoint or grant the permission
The change does not appear The metadata document is cached per server process (src/cluster_erp/server/app.py:1530-1543) Restart the server

Terms introduced

Term Code identifier Definition Turkish term Source
sidebar section SidebarSectionMeta One screen of a module, shown as a tab of its module app. kenar çubuğu bölümü src/cluster_erp/core/metadata.py:664

Verified against commit 92f8051 on 2026-11-13.

Verified against commit 92f8051 · 2026-11-13