MetaModelService / PageSchemaService

MetaModelService and PageSchemaService are the canonical read APIs for AuraBoot's metadata catalog — every model, field, and page definition contributed by core or by an installed plugin. They hide the on-disk JSON layout, plugin overlay precedence, and cache resolution behind a set of in-memory lookup methods.

Concept

At plugin import time, the host parses models.json, pages.json, commands.json, bindingRules.json, permissions.json, etc. from every plugin and merges them into a single tenant-scoped metadata catalog. Subsequent calls to MetaModelService go through the in-memory cache. The metadata is read-only at runtime; mutations go through the import path and trigger a cache refresh.

To answer "what fields does model X have?", use these services — never re-parse the JSON yourself.

Interface signature

package com.auraboot.framework.meta.service;

public interface MetaModelService {

    Optional<ModelDefinition> getModelDefinition(String modelCode);

    FieldDefinition           getFieldDefinition(String modelCode, String fieldCode);
    List<FieldDefinition>     getModelFields(String modelCode);   // all fields of the model

    /** Dynamic table name for a model — e.g. "crm_lead" → "mt_crm_lead". */
    String getTableName(String modelCode);

    boolean isModelExists(String modelCode);
    boolean isFieldExists(String modelCode, String fieldCode);

    void refreshModelCache(String modelCode);
}

Page definitions are served by the separate PageSchemaService:

package com.auraboot.framework.meta.service;

public interface PageSchemaService {

    PageSchemaDTO        findByPageKey(String pageKey);          // e.g. "crm_lead-list"
    List<PageSchemaDTO>  findByModelCode(String modelCode);      // list/form/detail kinds
    List<PageSchemaDTO>  findByKind(String kind);
}

ModelDefinition and FieldDefinition are Lombok @Data DTOs with raw config plus convenience accessors (isRequired(), isSearchable(), isDisplayField(), getDefaultValue()).

Implementation example

A custom report service that builds a column list dynamically from a model's field definitions:

package com.acme.report;

import com.auraboot.framework.meta.service.MetaModelService;
import com.auraboot.framework.meta.dto.FieldDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ReportColumnService {

    @Autowired private MetaModelService metaModelService;

    public List<ReportColumn> columnsFor(String modelCode) {
        return metaModelService.getModelFields(modelCode).stream()
            .filter(FieldDefinition::isSearchable)
            .map(f -> new ReportColumn(
                f.getCode(),
                f.getDisplayName(),
                f.getDataType(),
                f.isRequired()))
            .toList();
    }
}

A page-aware example that resolves the dynamic table for a list page:

PageSchemaDTO page  = pageSchemaService.findByPageKey("crm_lead-list");
String        table = metaModelService.getTableName(page.getModelCode());  // "mt_crm_lead"

Registration

MetaModelService and PageSchemaService are both host-managed Spring beans. Inject them via @Autowired from any plugin extension or platform service. There is no SPI to implement — they are services, not extension points. The metadata cache is refreshed automatically on plugin enable/disable and on model.published events.

Common pitfalls

  • Calling getTableName(modelCode) and assuming ab_dyn_<code>. The actual prefix is mt_<modelCode> (constant SystemFieldConstants.DYNAMIC_TABLE_PREFIX, see red line §15). Always call the API.
  • Caching ModelDefinition / FieldDefinition references across plugin reload. The cache refresh produces new instances; old references are stale. Cache the code and look up on demand.
  • Reading JSON files directly. Bypasses overlay precedence and validation. Always go through the service.
  • Assuming findByPageKey(modelCode + "-list") returns a user-defined page. MetaModelServiceImpl.autoCreateDefaultPages silently creates empty stubs on model publish — check whether its blocks are empty before treating it as real.

Related