Documentación de Configuración del Editor Genérico CRUD
Esta documentación proporciona especificaciones de configuración para los archivos JSON del Editor Genérico CRUD.
Directorio de configuración
El directorio de configuración es donde se almacenan los archivos JSON del Editor Genérico CRUD. La estructura de directorio sugerida es:
.
├── CHANGELOG.md
├── README.md
├── backend
│ ├── app_main_menu.json
│ ├── endpoints.json
│ ├── general_config.json
│ ├── users.json
│ └── users_config.json
└── frontend
├── app_constants.json
├── general_config.json
├── general_constants.json
├── users.json
├── users_config.json
└── users_profile.json
Configuración del Frontend
La configuración del frontend define el comportamiento general del editor CRUD y es utilizada tanto por el frontend como por el backend.
La configuración del frontend se encuentra en el directorio frontend.
En el directorio de configuración del frontend, hay varios archivos JSON, la mayoría son configuraciones del editor CRUD, y hay tres archivos especiales:
app_constants.jsongeneral_constants.jsongeneral_config.json
Consulta la sección Directorio Frontend en la guía Generación y Configuración de GenericSuite App para más detalles.
Validación
La configuración de validación define las reglas de validación para el editor CRUD.
Las interfaces de TypeScript para validar las configuraciones JSON del frontend se definen en el archivo CrudEditorConfigInterface.ts (FrontendCrudEditorConfig, ParentKeyName, FieldElement, FieldType).
Las clases de Python para validar las configuraciones JSON del frontend se definen en el archivo crud_editor_config_classes.py (FrontendCrudEditorConfig, ParentKeyName, FieldElement, FieldType).
Configuración General
Los archivos JSON para cada tabla o editor CRUD en el ejemplo son users.json, users_config.json y users_profile.json.
Para esos archivos, la sección de configuración general define el comportamiento global del editor CRUD.
Los siguientes atributos se utilizan en la sección de configuración general:
-
baseUrl: La URL del enrutador de ReactJS para el editor CRUD.
- Ejemplo:
ai_chatbot_conversations
- Ejemplo:
-
title: El título del editor CRUD, utilizado en la página de listado.
- Ejemplo: "AI Assistant Conversations" → "Conversaciones del Asistente AI"
-
name: El nombre del componente del editor CRUD, utilizado como título en la página de envío del formulario.
- Ejemplo: "AI Assistant Conversation" → "Conversación del Asistente AI"
-
component: El nombre del componente de ReactJS utilizado por el editor CRUD. Este componente es el pegamento entre el archivo .json y el registro de dependencias (o componentes relacionados).
- Ejemplo:
AiChatBotConversations
- Ejemplo:
-
dbApiUrl: La URL del endpoint de la API con la que interactúa el editor CRUD.
- Ejemplo:
ai_chatbot_conversations
- Ejemplo:
-
primaryKeyName: Nombre del parámetro de clave primaria para las llamadas a la API
- Ejemplo:
id
- Ejemplo:
-
defaultOrder: El orden predeterminado especifica los criterios de clasificación de los datos obtenidos de la base de datos en la página de listado.
- Ejemplo:
defaultOrder": "update_date|descordena los datos porupdate_dateen orden descendente.
- Ejemplo:
-
mandatoryFilters: Los filtros obligatorios se utilizan para restringir el acceso a ciertos campos o datos. Si se especifica,
mandatoryFiltersDbListPreReadse añadirá adbListPreReadymandatoryFiltersDbPreReadse añadirá a las funciones específicas dedbPreRead.- Ejemplo:
"mandatoryFilters": {
"user_id": "{CurrentUserId}"
},
-
userIdFilter: Si se debe añadir el filtro de ID de usuario actual a la página de listado. Es una alternativa al ejemplo anterior dado para el atributo
mandatoryFilters.- Ejemplo:
trueofalse
- Ejemplo:
-
fieldElements: Lista de elementos de campo a utilizar en el editor de listado secundario. Más detalles en la sección Field Elements.
Relaciones 1 a N
- childComponents: Lista de componentes secundarios relacionados con la tabla principal.
- Ejemplo: para tener listados secundarios con los componentes
Users HistoryyUsers Configurationrelacionados con la tabla principalUsers:
- Ejemplo: para tener listados secundarios con los componentes
"childComponents": [
"UsersUserHistory",
"UsersConfig"
],
-
type: tipo de editor. Use
child_listingpara los editores secundarios (relación 1 a muchos), omaster_listingpara el editor principal. Por defecto esmaster_listing.- Ejemplo:
child_listingomaster_listing
- Ejemplo:
-
subType: indica al backend cómo almacenar la relación 1 a muchos. Use
arraypara ítems de relación almacenados en la misma tabla padre como un elemento de arreglo. Usetablepara ítems de relación almacenados en una tabla diferente.- Ejemplo:
arrayotable
- Ejemplo:
-
array_name: nombre de atributo para el listado hijo tipo
array. Por ejemplo, si la tabla padre es "table_x_header" y la tabla hija es "table_x_lines", elarray_namepodría ser "table_x_lines".- Ejemplo:
table_x_lines
- Ejemplo:
-
parentUrl: la URL de la tabla padre que se utilizará en ciertas funciones específicas (porque el nombre de la tabla padre está definido en el archivo JSON de backend como atributo
table_namey el frontend no tiene acceso a él).- Ejemplo:
userspara el endpoint/v1/users.
- Ejemplo:
-
endpointKeyNames: Arreglo de nombres de claves utilizado al hacer llamadas a la API al backend para obtener los ítems del listado hijo. Esto se usa para establecer la relación entre las tablas padre e hijo (relación 1 a muchos). Cada elemento del arreglo debe tener los siguientes atributos:
parameterName: el nombre del parámetro que se utilizará en la llamada a la API del backend (endpoint) para identificar la clave primaria/clave de clasificación de la tabla padre.parentElementName: el nombre del atributo de la tabla padre cuyo valor se utilizará para identificar la clave primaria/clave de clasificación de la tabla padre.- Ejemplo:
"type": "child_listing",
"subType": "array",
"array_name": "users_config",
"parentUrl": "users",
"endpointKeyNames": [
{
"parameterName": "user_id",
"parentElementName": "id"
}
],
- allow_duplicates: Permitir duplicados en la creación de ítems del listado hijo. Por defecto es
false.- Ejemplo:
trueofalse
- Ejemplo:
Elementos de Campo
Los elementos de campo definen los campos individuales utilizados en el editor CRUD.
-
name: El nombre del elemento de campo.
-
label: La etiqueta mostrada para el campo.
-
type: El tipo de dato del campo o
field typepara el elemento de campo. Consulta Field data types para más detalles. -
required: Si el campo es obligatorio para el envío.
- Ejemplo:
true,false
- Ejemplo:
-
listing: Si el campo debe mostrarse en la página de listado.
- Ejemplo:
true,false
- Ejemplo:
-
readonly: Si el campo debe ser de solo lectura.
- Ejemplo:
true,false
- Ejemplo:
-
primaryKey: Si el campo es la clave primaria de la tabla.
- Ejemplo:
true,false
- Ejemplo:
-
default_value: El valor por defecto a usar para el campo cuando se carga la página de datos del formulario.
- Ejemplo:
0ocurrent_timestamp.current_timestampserá reemplazado por la fecha/hora actuales.
- Ejemplo:
-
hidden: Si el campo debe estar oculto de la visualización.
- Ejemplo:
true,false
- Ejemplo:
-
formula: para obtener el valor del campo desde un componente ReactJS. Consulta la sección Formulas para más detalles.
Tipos de datos de campo
-
text: genera un campo de entrada de texto (una sola línea).
-
textarea: genera un campo de entrada de textarea (multilínea).
-
number: genera un campo de entrada numérica (flotante).
-
integer: genera un campo de entrada entero (sin decimales).
-
date: genera un campo de entrada de fecha (solo fecha).
-
datetime-local: genera un campo de entrada datetime-local (fecha y hora).
-
array: genera un campo de arreglo multidimensional, como el tipo
dicten Python.- Ejemplos:
"array": [
{
"key1": "value1",
"key2": "value2"
}
]
"array": {
"key1": {
"key2": "value2"
}
}
-
email: genera un campo de entrada de correo electrónico (y lo valida durante la entrada).
-
label: genera una etiqueta sin campo de entrada.
-
h1, h2, h3, h4, h5, h6: generan un encabezado con el nivel especificado.
-
hr: genera una regla horizontal.
-
_id: genera un campo oculto con el valor de la clave primaria del objeto actual.
-
select: genera un campo de entrada de selección a partir de una lista de opciones.
-
select_table: genera un campo de entrada de selección a partir de una lista de ítems en una tabla relacionada.
-
select_component: genera un campo de entrada de selección con un componente ReactJS que rellena las opciones desde la base de datos.
-
suggestion_dropdown: genera un campo de entrada con un desplegable de sugerencias desde la base de datos o una llamada a API. Consulta la sección Suggestion Dropdowns para más detalles.
-
component: muestra un valor generado por un componente ReactJS.
Definiciones de botones especiales
Hay botones especiales que pueden usarse en los elementos de campo. Estos botones aparecerán en la página de datos del formulario solo en el lado derecho del campo.
Los botones se habilitan mediante los atributos chatbot_popup y google_popup del elemento de campo, y los atributos chatbot_prompt y google_prompt se utilizan para definir el texto que se utilizará al llamar al correspondiente componente ReactJS.
Las definiciones de botones especiales son opcionales.
-
chatbot_popup: genera un botón que utiliza el componente ReactJS
ChatBotButtonque abre un popup para interactuar con el AI Assistant. Por defecto esfalse.- Ejemplo:
chatbot_popup: true.
- Ejemplo:
-
chatbot_prompt: define el texto que se utilizará al llamar al componente ReactJS
ChatBotButton.- Ejemplo:
chatbot_prompt: "Dame toda la información para el tema %s". NOTA:%sserá reemplazado por el valor del campo.
- Ejemplo:
-
google_popup: genera un botón que llamará al componente ReactJS
SearchEngineButton. Por defecto esfalse.- Ejemplo:
google_popup: true
- Ejemplo:
-
google_prompt: define el texto que se utilizará al llamar al componente ReactJS
SearchEngineButton.- Ejemplo:
google_prompt: "%s calories en KCAL, cantidad de porción y unidad de porción". NOTA:%sserá reemplazado por el valor del campo.
- Ejemplo:
Desplegables de sugerencias
Los desplegables de sugerencias se utilizan para rellenar el valor del campo de entrada con sugerencias mostradas en una lista desplegable poblada por una base de datos o una llamada a API mientras el usuario escribe.
Las sugerencias se rellenan desde una URL de API definida en el atributo filter_api_url, y el atributo filter_api_request_method define el método HTTP a utilizar para llamar a la API.
El atributo suggestion_id_fieldname define el nombre del campo en la respuesta de la API que se utilizará para identificar la clave del elemento seleccionado en el desplegable.
El atributo suggestion_desc_fieldname define el nombre del campo en la respuesta de la API que se utilizará para mostrar el nombre del elemento seleccionado en el desplegable.
El atributo filter_search_param_name define el nombre del parámetro que se utilizará en la llamada a la API para identificar el término de búsqueda.
El atributo filter_search_other_param es un diccionario que define los otros parámetros a usar en la llamada a la API para identificar el término de búsqueda.
El atributo autocomplete_fields es un diccionario que define los campos que se completarán desde el elemento seleccionado en el desplegable. La clave es el nombre del campo en el formulario, y el valor es el nombre del campo de la respuesta de la API.
{
"name": "name",
"required": true,
"label": "Name",
"readonly": false,
"listing": true,
"type": "suggestion_dropdown",
"suggestion_id_fieldname": "_id",
"suggestion_desc_fieldname": "name",
"filter_api_url": "user_ingredients",
"filter_api_request_method": "GET",
"filter_search_param_name": "name",
"filter_search_other_param": {
"like": "1",
"user_id": "{CurrentUserId}"
},
"autocomplete_fields": {
"calories_value": "calories_value",
"calories_unit": "calories_unit",
"serving_size": "serving_size",
"serving_size_unit": "serving_size_unit",
"brand_name": "brand_name",
"observations": "observations"
},
"chatbot_popup": true,
"aux_component": "ChatBotButton",
"chatbot_prompt": "Dame las %s calorías en KCAL incluyendo la cantidad de porción y la unidad de porción. Busca primero en mis ingredientes, si no está, busca con la herramienta web_search.",
"google_popup": true,
"google_prompt": "%s calorías KCAL"
},
Funciones específicas
Funciones que amplían la funcionalidad del editor CRUD desde la perspectiva del frontend. Están destinadas a usarse antes y después de las operaciones de base de datos: leer, escribir, eliminar y validaciones.
Cada valor de función específica es una lista (arrays) de funciones ReactJS que se ejecutarán en el orden en que aparecen.
Todas las funciones específicas son opcionales.
- dbListPreRead: Antes de leer datos desde la base de datos en la página de listado. Un buen lugar para filtros ocultos.
- Ejemplo:
"dbListPreRead": [
"UsersDbListPreRead"
],
-
dbListPostRead: Después de leer datos desde la base de datos en la página de listado. Al final de la lista,
timestampDbListPostReadsiempre se añadirá para realizar la conversión de Timestamp a Date de los campos de tipodateydatetime-local. -
dbPreRead: Antes de leer datos desde la base de datos en formData. Si hay algún error, muestra el mensaje de error.
-
dbPostRead: Después de leer datos desde la base de datos en formData. Si hay algún error, muestra el mensaje de error. Al final de la lista,
timestampDbPostReadsiempre se añadirá para realizar la conversión de Timestamp a Date de los campos de tipodateydatetime-local. -
dbPreValidations: Validación de valores de campos de FormData antes de realizar una operación de Delete. Si hay algún error, impide que se elimine la fila de la base de datos.
- Ejemplo:
"dbPreValidations": [
"UsersValidations"
],
- validations: Validación de valores de campos de FormData antes de escribir en la base de datos. Si hay algún error, impide la escritura en la base de datos y se mantiene en FormData.
- Ejemplo:
"validations": [
"UsersPasswordValidations"
]
- dbPreWrite: Antes de escribir en la base de datos, tras una validación exitosa. Si hay algún error, muestra el mensaje de error, impide la escritura en la base de datos y se mantiene en FormData.
- Ejemplo:
"dbPreWrite": [
"UsersDbPreWrite"
],
Al final de la lista, por defecto se añadirá timestampDbPreWrite para manejar la asignación de timestamp a los campos de tipo date y datetime-local. Si update_date no existe en el formulario, se asignará el timestamp actual.
- dbPostWrite: Después de una escritura exitosa en la base de datos. Si hay algún error, muestra el mensaje de error y se mantiene en FormData.
- Ejemplo:
"dbPostWrite": [
"UsersDbPostWrite"
],
Formulas
Las Formulas se utilizan para calcular los valores de los campos a partir de otros campos.
Ejemplo: en un formulario de Pedido con una relación de 1 a muchos con las Líneas de Pedido, el campo total podría tener totalCalcInOrderLine en el atributo formula y el correspondiente componente ReactJS podría ser:
export const totalCalcInOrderLine = () => {
// Calcula el precio total de las líneas de pedido multiplicando el precio por la cantidad
const response = (parseFloat(document.getElementsByName('price')[0].value) * parseFloat(document.getElementsByName('quantity')[0].value)).toFixed(2);
return response;
}
Para calcular el grand_total de la página de datos del formulario, debe existir una función específica de dbPostWrite en el componente hijo de Líneas de Pedido, por ej. granTotalFromOrderLines y el componente ReactJS podría ser:
const dbApiService = gs.dbService.dbApiService;
const genericFuncArrayDefaultValue = gs.genericEditorRfcSpecificFunc.genericFuncArrayDefaultValue;
const ACTION_DELETE = gs.generalConstants.ACTION_DELETE;
const ACTION_CREATE = gs.generalConstants.ACTION_CREATE;
const ACTION_UPDATE = gs.generalConstants.ACTION_UPDATE;
export const granTotalFromOrderLines = ({
data,
editor,
action,
}) => {
return new Promise((resolve, reject) => {
let resp = genericFuncArrayDefaultValue(data);
let grand_total = 0;
const parentId = editor.parentData[editor.endpointKeyNames[0].parentElementName];
let childFilter = {};
childFilter[editor.endpointKeyNames[0].parameterName] = parentId;
switch(action) {
case ACTION_CREATE:
case ACTION_UPDATE:
case ACTION_DELETE:
const db = new dbApiService({ url: editor.parentUrl });
// Obtener los datos del ítem padre
db.getOne({id: parentId}).then(
data => {
if (!data['resultset']) {
resp.error = true;
resp.errorMsg = (resp.errorMsg === '' ? '' : '<br>') +
`Cannot read Parent Table ID: ${parentId}`;
}
if (resp.error) {
reject(resp);
} else {
// Obtener los datos de los ítems hijos
const db2 = new dbApiService({ url: editor.dbApiUrl });
db2.getAll(childFilter).then(
data2 => {
// Calcular el total general sumando los ítems hijos
grand_total = data2['resultset'].reduce( (total, row) => {
total += (row["quantity"] * row["price"]);
return total;
}, 0)
// Actualizar el ítem padre con el grand total
let itemToSave = (data['resultset']);
itemToSave["grand_total"] = grand_total.toFixed(2);
delete itemToSave["_id"];
db.updateRow(parentId, itemToSave).then(
_ => {
// Refrescar el padre (tabla principal) form data una vez que los ítems hijos se actualicen en la base de datos
resp['otherData']['refresh'] = true;
resolve(resp);
},
error => {
resp.error = true;
resp.errorMsg = error;
reject(resp)
}
);
},
error => {
resp.error = true;
resp.errorMsg = error;
reject(resp)
}
);
}
},
error => {
resp.error = true;
resp.errorMsg = error;
reject(resp)
}
);
break;
default:
resolve(resp);
}
});
}
Configuración Backend
Esta configuración es utilizada exclusivamente por el backend.
Validación
Las interfaces de TypeScript para validar las configuraciones JSON del backend se definen en el archivo CrudEditorConfigInterface.ts (BackendCrudEditorConfig).
Las clases de Python para validar las configuraciones JSON del backend se definen en el archivo crud_editor_config_classes.py (BackendCrudEditorConfig).
Atributos de la Configuración Backend
- table_name: nombre físico de la tabla en la base de datos.
- Ejemplo:
"table_name": "users",
- creation_pk_name: nombre de la columna/atributo en la base de datos utilizado como clave primaria para la tabla durante el proceso de creación.
- Ejemplo:
"creation_pk_name": "email",
- projection_exclusion: lista de atributos a excluir de la proyección.
- Ejemplo:
"projection_exclusion": [
"passcode"
],
- email_verification: lista de atributos que deben validarse como direcciones de correo.
- Ejemplo:
"email_verification": [
"email"
],
- passwords: lista de atributos que deben validarse como contraseñas.
- Ejemplo:
"passwords": [
"passcode"
],
- mandatory_fields: lista de atributos que deben estar presentes en la tabla.
- Ejemplo:
"mandatory_fields": [
"firstname",
"lastname",
"creation_date",
"gender",
"birthday",
"email"
],
- additional_query_params: lista de atributos que se deben usar en las operaciones de consulta distintas de la clave primaria.
- Ejemplo:
"additional_query_params": [
"email"
],
- specific_function: función específica a ejecutar antes y después de las operaciones de base de datos.
- Ejemplos:
"specific_function": "delete_params_file"
"specific_function": "app_other_specific_function"
IMPORTANTE: para funciones específicas no estándar como "delete_params_file", la función debe estar implementada en el backend:
from genericsuite_ai.fastapilib.util.create_app import (
create_app,
create_handler
)
from app.config.config import Config
# Importa la función específica
from app.specific_functions import app_other_specific_function
settings = Config()
app = create_app(
app_name=f"{settings.APP_NAME.lower()}-backend", settings=settings)
# Registra la función específica
app.custom_data['app_other_specific_function'] = app_other_specific_function
handler = create_handler(app)
Ejemplos
Veamos algunos ejemplos de archivos de configuración usando una App hipotética GenericSuite Example App para seguir calorías y crear planes de comidas. Los archivos de configuración se encuentran en el directorio exampleapp/apps/config_dbdef.
Estructura de Directorios
exampleapp/apps/config_dbdef/
├── backend/
| ├── ai_chatbot_conversations.json # Conversaciones de IA Chatbot para la interfaz de Chatbot
| ├── app_main_menu.json # Configuración del menú principal de la App
| ├── clarifai_models.json # Modelos de IA de Clarifai
| ├── daily_meal_ingredients.json # Ingredientes de comidas diarias del usuario
| ├── daily_meals.json # Lista de comidas diarias del usuario
| ├── dish_ingredients.json # Ingredientes de los platos del usuario
| ├── dishes.json # Lista de platos del usuario
| ├── endpoints.json # Configuración de endpoints de la API backend de la App
| ├── food_moments.json # Tipos de comida generales (o momentos)
| ├── general_config.json # Parámetros de configuración dinámica de la App
| ├── general_ingredients.json # Ingredientes globales
| ├── user_ingredients_all.json # Todos los ingredientes del usuario
| ├── user_ingredients.json # Ingredientes del usuario
| ├── users_api_keys.json # Claves API del usuario
| ├── users_config.json # Parámetros de configuración del usuario
| ├── users_food_times.json # Tiempos típicos de ingesta de comidas del usuario
| ├── users_profile.json # Página de perfil del usuario
| ├── users_user_history.json # Historial de datos del usuario (objetivos, peso, etc.)
| ├── users.json # Usuarios
├── frontend/
| ├── ai_chatbot_conversations_complete.json # Conversaciones de IA Chatbot para un editor CRUD
| ├── ai_chatbot_conversations.json # Conversaciones de IA Chatbot para la interfaz de Chatbot
| ├── app_constants.json # Constantes generales de la App (planes de facturación, unidades, tipos, códigos, género, correos, URLs, etc.)
| ├── clarifai_models.json # Modelos de IA de Clarifai
| ├── daily_meal_ingredients.json # Ingredientes de comidas diarias del usuario
| ├── daily_meals.json # Lista de comidas diarias del usuario
| ├── dish_ingredients.json # Ingredientes de los platos del usuario
| ├── dishes.json # Lista de platos del usuario
| ├── food_moments.json # Tipos de comida generales (o momentos)
| ├── general_config.json # Parámetros de configuración dinámica de la App
| ├── general_constants.json # Constantes generales de la App (true/false, yes/no, idiomas, géneros, etc.)
| ├── general_ingredients.json # Ingredientes globales
| ├── user_ingredients_all.json # Todos los ingredientes del usuario
| ├── user_ingredients.json # Ingredientes del usuario
| ├── users_api_keys.json # Claves API del usuario
| ├── users_config.json # Parámetros de configuración del usuario
| ├── users_food_times.json # Tiempos típicos de ingesta de comidas del usuario
| ├── users_profile.json # Página de perfil del usuario
| ├── users_user_history.json # Historial de datos del usuario (objetivos, peso, etc.)
| ├── users.json # Usuarios
├── .gitignore
├── CHANGELOG.md
├── package.json
├── README.md
backend/ai_chatbot_conversations.json
Conversaciones de IA Chatbot para la interfaz de Chatbot
{
"table_name": "ai_chatbot_conversations",
"creation_pk_name": "_id",
"additional_query_params": [
"_id"
]
}
backend/app_main_menu.json
Configuración del menú principal de la App
[
{
"title": "Home",
"location": "top_menu",
"type": "nav_link",
"path": "/",
"element": "HomePage",
"hard_prefix": false,
"reload": true
},
{
"title": "Admin",
"location": "top_menu",
"type": "nav_dropdown",
"sec_group": "admin",
"sub_menu_options": [
{
"type": "editor",
"sec_group": "admin",
"title": "Users",
"element": "Users_EditorData"
},
{
"type": "editor",
"sec_group": "admin",
"title": "Meal Types",
"element": "FoodMoments_EditorData"
},
{
"type": "editor",
"sec_group": "admin",
"title": "General Ingredients",
"element": "GeneralIngredients_EditorData"
},
{
"type": "editor",
"sec_group": "admin",
"title": "General Config",
"element": "GeneralConfig_EditorData"
},
{
"type": "editor",
"sec_group": "admin",
"title": "Clarifai Models",
"element": "ClarifaiModels_EditorData"
}
]
},
{
"title": "Foods",
"location": "top_menu",
"type": "nav_dropdown",
"sec_group": "users",
"sub_menu_options": [
{
"type": "editor",
"sec_group": "users",
"title": "Ingredients",
"element": "UserIngredients_EditorData"
},
{
"type": "editor",
"sec_group": "users",
"title": "Dishes",
"element": "Dishes_EditorData"
},
{
"type": "editor",
"sec_group": "users",
"title": "Daily Meals",
"element": "DailyMeals_EditorData"
}
]
},
{
"title": "ExampleApp Bot",
"location": "top_menu",
"type": "nav_link",
"sec_group": "users",
"path": "/chatbot",
"element": "Chatbot"
},
{
"title": "User Menu",
"location": "hamburger",
"sub_menu_options": [
{
"title": "Profile",
"path": "/profile",
"element": "UserProfileEditor"
},
{
"title": "Preferences",
"path": "#preferences",
"element": "PreferencesEditor"
},
{
"title": "About",
"on_click": "|about|"
},
{
"title": "Logout",
"path": "/logout",
"on_click": "logout"
}
]
},
{
"title": "Other Routes",
"sub_menu_options": [
{
"title": "Absolut Home",
"path": "/",
"element": "HomePage",
"get_prefix": false
},
{
"title": "About body",
"path": "/about_body",
"element": "AboutBody",
"get_prefix": false
}
]
}
]
backend/clarifai_models.json
Modelos de IA de Clarifai
{
"table_name": "clarifai_models",
"creation_pk_name": "model_name",
"additional_query_params": [
"model_name"
]
}
backend/daily_meal_ingredients.json
Ingredientes de comidas diarias del usuario
{
"table_name": "daily_meals"
}
backend/daily_meals.json
Lista de comidas diarias del usuario
{
"table_name": "daily_meals"
}
backend/dish_ingredients.json
Ingredientes de los platos del usuario
{
"table_name": "user_ingredients",
"notes": "'dishes' are 'user_ingredients' with type 'D'"
}
backend/dishes.json
Lista de platos del usuario
{
"table_name": "user_ingredients",
"notes": "'dishes' are 'user_ingredients' with type 'D'",
"creation_pk_name": "name",
"additional_query_params": [
"name"
]
}
backend/endpoints.json
Configuración de endpoints de la API backend de la App
[
{
"name": "food_moments",
"url_prefix": "food_moments",
"routes": [
{
"endpoint": "/",
"methods": ["GET", "POST", "PUT", "DELETE"],
"handler_type": "GenericEndpointHelper",
"view_func": "lib.util.generic_endpoint_builder.generic_route_handler",
"params": {
"json_file": "food_moments"
}
}
]
},
{
"name": "general_ingredients",
"url_prefix": "general_ingredients",
"routes": [
{
"endpoint": "/",
"methods": ["GET", "POST", "PUT", "DELETE"],
"handler_type": "GenericEndpointHelper",
"view_func": "lib.util.generic_endpoint_builder.generic_route_handler",
"params": {
"json_file": "general_ingredients"
}
}
]
},
{
"name": "user_ingredients",
"url_prefix": "user_ingredients",
"routes": [
{
"endpoint": "/",
"methods": ["GET", "POST", "PUT", "DELETE"],
"handler_type": "GenericEndpointHelper",
"view_func": "lib.util.generic_endpoint_builder.generic_route_handler",
"params": {
"json_file": "user_ingredients"
}
}
]
},
{
"name": "user_ingredients_all",
"url_prefix": "user_ingredients_all",
"routes": [
{
"endpoint": "/",
"methods": ["GET", "POST", "PUT", "DELETE"],
"handler_type": "GenericEndpointHelper",
"view_func": "lib.util.generic_endpoint_builder.generic_route_handler",
"params": {
"json_file": "user_ingredients_all"
}
}
]
},
{
"name": "dishes",
"url_prefix": "dishes",
"routes": [
{
"endpoint": "/",
"methods": ["GET", "POST", "PUT", "DELETE"],
"handler_type": "GenericEndpointHelper",
"view_func": "lib.util.generic_endpoint_builder.generic_route_handler",
"params": {
"json_file": "dishes"
}
}
]
},
{
"name": "dish_ingredients",
"url_prefix": "dish_ingredients",
"routes": [
{
"endpoint": "/",
"methods": ["GET", "POST", "PUT", "DELETE"],
"handler_type": "GenericEndpointHelper",
"view_func": "lib.util.generic_endpoint_builder.generic_route_handler",
"params": {
"json_file": "dish_ingredients"
}
}
]
},
{
"name": "daily_meals",
"url_prefix": "daily_meals",
"routes": [
{
"endpoint": "/",
"methods": ["GET", "POST", "PUT", "DELETE"],
"handler_type": "GenericEndpointHelper",
"view_func": "lib.util.generic_endpoint_builder.generic_route_handler",
"params": {
"json_file": "daily_meals"
}
}
]
},
{
"name": "daily_meal_ingredients",
"url_prefix": "daily_meal_ingredients",
"routes": [
{
"endpoint": "/",
"methods": ["GET", "POST", "PUT", "DELETE"],
"handler_type": "GenericEndpointHelper",
"view_func": "lib.util.generic_endpoint_builder.generic_route_handler",
"params": {
"json_file": "daily_meal_ingredients"
}
}
]
},
{
"name": "ai_chatbot_conversations",
"url_prefix": "ai_chatbot_conversations",
"routes": [
{
"endpoint": "/",
"methods": ["GET", "POST", "PUT", "DELETE"],
"handler_type": "GenericEndpointHelper",
"view_func": "lib.util.generic_endpoint_builder.generic_route_handler",
"params": {
"json_file": "ai_chatbot_conversations"
}
}
]
},
{
"name": "general_config",
"url_prefix": "general_config",
"routes": [
{
"endpoint": "/",
"methods": ["GET", "POST", "PUT", "DELETE"],
"handler_type": "GenericEndpointHelper",
"view_func": "lib.util.generic_endpoint_builder.generic_route_handler",
"params": {
"json_file": "general_config"
}
}
]
},
{
"name": "users",
"url_prefix": "users",
"routes": [
{
"endpoint": "/",
"methods": ["GET", "POST", "PUT", "DELETE"],
"handler_type": "GenericEndpointHelper",
"view_func": "lib.util.generic_endpoint_builder.generic_route_handler",
"params": {
"json_file": "users"
}
}
]
},
{
"name": "users_config",
"url_prefix": "users_config",
"routes": [
{
"endpoint": "/",
"methods": ["GET", "POST", "PUT", "DELETE"],
"handler_type": "GenericEndpointHelper",
"view_func": "lib.util.generic_endpoint_builder.generic_route_handler",
"params": {
"json_file": "users_config"
}
}
]
},
{
"name": "users_food_times",
"url_prefix": "users_food_times",
"routes": [
{
"endpoint": "/",
"methods": ["GET", "POST", "PUT", "DELETE"],
"handler_type": "GenericEndpointHelper",
"view_func": "lib.util.generic_endpoint_builder.generic_route_handler",
"params": {
"json_file": "users_food_times"
}
}
]
},
{
"name": "users_user_history",
"url_prefix": "users_user_history",
"routes": [
{
"endpoint": "/",
"methods": ["GET", "POST", "PUT", "DELETE"],
"handler_type": "GenericEndpointHelper",
"view_func": "lib.util.generic_endpoint_builder.generic_route_handler",
"params": {
"json_file": "users_user_history"
}
}
]
},
{
"name": "users_api_keys",
"url_prefix": "users_api_keys",
"routes": [
{
"endpoint": "/",
"methods": ["GET", "POST", "PUT", "DELETE"],
"handler_type": "GenericEndpointHelper",
"view_func": "lib.util.generic_endpoint_builder.generic_route_handler",
"params": {
"json_file": "users_api_keys"
}
}
]
},
{
"name": "clarifai_models",
"url_prefix": "clarifai_models",
"routes": [
{
"endpoint": "/",
"methods": ["GET", "POST", "PUT", "DELETE"],
"handler_type": "GenericEndpointHelper",
"view_func": "lib.util.generic_endpoint_builder.generic_route_handler",
"params": {
"json_file": "clarifai_models"
}
}
]
}
]
backend/food_moments.json
Lista general de tipos de comida (o momentos)
{
"table_name": "food_moments",
"creation_pk_name": "name",
"additional_query_params": [
"name"
]
}
backend/general_config.json
Parámetros de configuración dinámica de la App
{
"table_name": "general_config",
"creation_pk_name": "config_name",
"additional_query_params": [
"config_name"
],
"specific_function": "delete_params_file"
}
backend/general_ingredients.json
Ingredientes globales
{
"table_name": "general_ingredients",
"creation_pk_name": "name",
"additional_query_params": [
"name"
]
}
backend/user_ingredients_all.json
Todos los ingredientes del usuario
{
"table_name": "user_ingredients",
"creation_pk_name": "name",
"additional_query_params": [
"name"
]
}
backend/user_ingredients.json
Ingredientes del usuario
{
"table_name": "user_ingredients",
"creation_pk_name": "name",
"additional_query_params": [
"name"
]
}
backend/users_api_keys.json
Claves API del usuario
{
"table_name": "users_api_keys",
"specific_function": "delete_params_file"
}
backend/users_config.json
Parámetros de configuración del usuario
{
"table_name": "users",
"specific_function": "delete_params_file"
}
backend/users_food_times.json
Tiempos típicos de ingesta de comidas del usuario
{
"table_name": "users"
}
backend/users_profile.json
Página de perfil del usuario
{
"table_name": "users",
"creation_pk_name": "email",
"projection_exclusion": [
"passcode"
],
"email_verification": [
"email"
],
"passwords": [
"passcode"
],
"mandatory_fields": [
"firstname",
"lastname",
"creation_date",
"gender",
"birthday",
"email",
"height",
"height_unit",
"weight",
"weight_unit",
"training_days",
"training_hour"
],
"additional_query_params": [
"email"
],
"specific_function": "delete_params_file"
}
backend/users_user_history.json
Historial de datos del usuario (objetivos, peso, etc.)
{
"table_name": "users"
}
backend/users.json
Usuarios
{
"table_name": "users",
"creation_pk_name": "email",
"projection_exclusion": [
"passcode"
],
"email_verification": [
"email"
],
"passwords": [
"passcode"
],
"mandatory_fields": [
"firstname",
"lastname",
"creation_date",
"gender",
"birthday",
"email"
],
"additional_query_params": [
"email"
]
}
frontend/ai_chatbot_conversations_complete.json
Conversaciones de IA Chatbot para un editor CRUD
{
"table_name": "ai_chatbot_conversations",
"creation_pk_name": "_id",
"additional_query_params": [
"_id"
],
"baseUrl": "ai_chatbot_conversations",
"title": "ExampleApp Bot Conversations",
"name": "ExampleApp Bot Conversation",
"component": "ExampleApp Bot Conversations",
"dbApiUrl": "ai_chatbot_conversations",
"mandatoryFilters": {
"user_id": "{CurrentUserId}"
},
"defaultOrder": "update_date|desc",
"fieldElements": [
{
"name": "id",
"label": "ID",
"type": "_id",
"listing": true,
"required": true
},
{
"name": "user_id",
"label": "User ID",
"type": "text",
"listing": true,
"required": true
},
{
"name": "title",
"label": "Title",
"type": "text",
"listing": true,
"required": true
},
{
"name": "creation_date",
"required": true,
"label": "Created",
"type": "datetime-local",
"listing": true
},
{
"name": "update_date",
"required": true,
"label": "Last update",
"type": "datetime-local",
"listing": true
},
{
"name": "messages",
"required": true,
"label": "Messages",
"type": "array",
"listing": true
}
]
}
frontend/ai_chatbot_conversations.json
Conversaciones de IA Chatbot para la interfaz de Chatbot
{
"baseUrl": "ai_chatbot_conversations",
"title": "ExampleApp Bot Conversations",
"name": "ExampleApp Bot Conversation",
"component": "ExampleApp Bot Conversations",
"dbApiUrl": "ai_chatbot_conversations",
"mandatoryFilters": {
"user_id": "{CurrentUserId}"
},
"defaultOrder": "update_date|desc",
"fieldElements": [
{
"name": "id",
"required": true,
"label": "ID",
"type": "_id",
"readonly": true,
"hidden": true
},
{
"name": "user_id",
"required": true,
"label": "User ID",
"type": "text",
"readonly": true,
"hidden": true
},
{
"name": "title",
"required": true,
"label": "Title",
"type": "text",
"readonly": true,
"listing": true
},
{
"name": "creation_date",
"required": true,
"label": "Created",
"type": "datetime-local",
"readonly": true,
"hidden": false,
"default_value": "current_timestamp",
"listing": true
},
{
"name": "update_date",
"required": true,
"label": "Last update",
"type": "datetime-local",
"readonly": true,
"hidden": false,
"default_value": "current_timestamp",
"listing": true
},
{
"name": "messages",
"required": true,
"label": "Messages",
"type": "array",
"readonly": true,
"listing": false
}
]
}
frontend/app_constants.json
Constantes generales de la App (planes de facturación, unidades, tipos, códigos, género, correos, URLs, etc.)
{
"WEIGHT_UNITS": {
"kg": "Kg",
"lb": "Libras"
},
"HEIGHT_UNITS": {
"m": "Metros",
"i": "Pulgadas"
},
"GENDERS": {
"m": "Masculino",
"f": "Femenino"
},
"CALORIE_UNITS": {
"kcal": "Calorías (KCAL)",
"kj": "KJoules (kj)"
},
"SERVING_SIZE_UNITS": {
"g": "Gramos (g)",
"u": "Unidad",
"tsp": "Cucharadita",
"tablespoon": "Cucharada",
"bowl": "Cuenco (300 ml)",
"cup": "Taza (200 ml)",
"scup": "Taza pequeña (150 ml)",
"ml": "Mililitros (ml)",
"mg": "Miligramos (mg)",
"ug": "Microgramos (ug)",
"oz": "Onza (oz)",
"lb": "Libra (lb)",
"iu": "Unidades internacionales (iu)",
"mlt": " Masa, longitud, tiempo (mlt)"
},
"INGREDIENT_TYPE": {
"I": "Ingrediente",
"D": "Plato"
},
"GOAL_CODES": {
"-20-DEFAULT": "Perder peso:",
"-10": "-10% descenso más lento pero más seguro (recomendado para conservar masa muscular y rendimiento)",
"-20": "-20% quiere perder peso para que sea algo más rápido",
"-30": "-30% urgencia para perder peso rápidamente o sufrir de obesidad",
"+20-DEFAULT": "Ganar peso:",
"+10": "+10% tiende a aumentar de peso o ha estado entrenando mucho tiempo y quiere ganar masa muscular",
"+15": "+15% quiere ganar un poco más de peso",
"+20": "+20% para ectomorfos o dificiles de ganar"
},
"BILLING_PLANS": {
"free": "Gratis",
"basic": "Básico",
"premium": "Premium"
},
"ERROR_MESSAGES": {
"ACCOUNT_INACTIVE": "Cuenta de usuario inactiva [L5]. Para activar su cuenta, póngase en contacto con support@exampleapp.com"
},
"APP_EMAILS": {
"SUPPORT_EMAIL": "support@exampleapp.com",
"INFO_EMAIL": "info@exampleapp.com"
},
"APP_VALID_URLS": {
"APP_DOMAIN": "exampleapp.com",
"APP_WEBSITE": "https://www.exampleapp.com"
},
"AI_PROMPT_TEMPLATES": {
"ASSISTANT_YOU_ARE": "{assistant_name}. Usted es parte de ExampleApp, una App que permite a las personas registrar sus ingredientes de comida favoritos, recetas y comidas diarias, rastrear el consumo de calorías y crear menús con déficit calórico basados en ingredientes y recetas asequibles y preferidos. Proporciona experiencias potenciadas por IA a las personas usando grandes modelos de lenguaje, reconocimiento de voz, texto a imagen y imagen a texto, permitiéndoles interactuar por voz, texto o carga de imágenes.",
"BOTTOM_LINE": "Si la información calórica no pudo recuperarse de la base de datos de la FDA, búscala en Internet y, si tampoco funciona, dedúcela de tu modelo."
}
}
frontend/clarifai_models.json
Modelos de IA de Clarifai
{
"baseUrl": "clarifai_models",
"title": "Clarifai Models",
"name": "Clarifai Model Configuration",
"component": "ClarifaiModels",
"dbApiUrl": "clarifai_models",
"defaultOrder": "model_name|asc",
"fieldElements": [
{
"name": "id",
"required": true,
"label": "ID",
"type": "_id",
"readonly": true
},
{
"name": "model_name",
"required": true,
"label": "Name",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "active",
"required": true,
"label": "Active",
"type": "select",
"select_elements": "TRUE_FALSE",
"readonly": false,
"hidden": false,
"default_value": "1",
"listing": true
},
{
"name": "user_id",
"required": true,
"label": "User ID",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "app_id",
"required": true,
"label": "App ID",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "model_id",
"required": true,
"label": "Model ID",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "model_version_id",
"required": true,
"label": "Model Version ID",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "model_url",
"required": false,
"label": "Model URL",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "notes",
"required": false,
"label": "Notes",
"type": "text",
"readonly": false,
"listing": true
}
]
}
frontend/daily_meal_ingredients.json
Ingredientes de comidas diarias del usuario
{
"baseUrl": "daily_meal_ingredients",
"title": "Meal Ingredients",
"name": "Meal Ingredient",
"dbApiUrl": "daily_meal_ingredients",
"component": "DailyMealIngredients",
"type": "child_listing",
"subType": "array",
"array_name": "meal_ingredients",
"parentUrl": "daily_meals",
"endpointKeyNames": [
{
"parameterName": "daily_meal_id",
"parentElementName": "id"
}
],
"primaryKeyName": "id",
"allow_duplicates": true,
"fieldElements": [
{
"name": "id",
"required": false,
"label": "ID",
"type": "text",
"readonly": true,
"hidden": true,
"listing": false,
"uuid_generator": true
},
{
"name": "meal_type",
"label": "Type",
"required": true,
"listing": true,
"type": "suggestion_dropdown",
"suggestion_id_fieldname": "_id",
"suggestion_desc_fieldname": "name",
"filter_api_url": "food_moments",
"filter_api_request_method": "GET",
"filter_search_param_name": "name",
"filter_search_other_param": {
"like": "1"
}
},
{
"name": "name",
"required": true,
"label": "Name",
"readonly": false,
"listing": true,
"type": "suggestion_dropdown",
"suggestion_id_fieldname": "_id",
"suggestion_desc_fieldname": "name",
"filter_api_url": "user_ingredients_all",
"filter_api_request_method": "GET",
"filter_search_param_name": "name",
"filter_search_other_param": {
"like": "1",
"user_id": "{CurrentUserId}"
},
"autocomplete_fields": {
"calories_value": "calories_value",
"calories_unit": "calories_unit",
"serving_size": "serving_size",
"serving_size_unit": "serving_size_unit",
"brand_name": "brand_name",
"observations": "observations"
},
"chatbot_popup": true,
"aux_component": "ChatBotButton",
"chatbot_prompt": "Dame las %s calorías en KCAL incluyendo la cantidad de porción y la unidad de porción. Busca primero en mis ingredientes, si no está, busca con la herramienta web_search.",
"google_popup": true,
"google_prompt": "%s calorías KCAL"
},
{
"name": "calories_value",
"required": true,
"label": "Calories",
"type": "number",
"readonly": false,
"listing": true
},
{
"name": "calories_unit",
"required": true,
"label": "Calories Unit",
"type": "select",
"select_elements": "CALORIE_UNITS",
"readonly": false,
"listing": true,
"default_value": "kcal"
},
{
"name": "serving_size",
"required": true,
"label": "Serving size",
"type": "number",
"readonly": false,
"listing": true
},
{
"name": "serving_size_unit",
"required": true,
"label": "Serving size unit",
"type": "select",
"select_elements": "SERVING_SIZE_UNITS",
"readonly": false,
"listing": true,
"default_value": "g"
},
{
"name": "quantity",
"required": true,
"label": "Qty.",
"type": "number",
"min": "0",
"max": "9999",
"readonly": false,
"listing": true
},
{
"name": "total_calories",
"label": "Total",
"type": "number",
"readonly": true,
"listing": true,
"formula": "totalCaloriesCalcInDailyMealIngredients"
},
{
"name": "brand_name",
"required": false,
"label": "Brand Name",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "observations",
"required": false,
"label": "Observations",
"type": "textarea",
"readonly": false,
"listing": true
}
],
"dbPostWrite": [
"DailyMealIngredientsDbPostWrite"
]
}
frontend/daily_meals.json
Lista de comidas diarias del usuario
{
"baseUrl": "daily_meals",
"title": "Daily Meals",
"name": "Daily Meal",
"component": "DailyMeals",
"dbApiUrl": "daily_meals",
"mandatoryFilters": {
"user_id": "{CurrentUserId}"
},
"createReenter": true,
"defaultOrder": "meal_date|desc",
"fieldElements": [
{
"name": "id",
"required": true,
"label": "ID",
"type": "_id",
"readonly": true,
"hidden": true
},
{
"name": "user_id",
"required": true,
"label": "User ID",
"type": "text",
"readonly": true,
"hidden": true
},
{
"name": "meal_date",
"required": true,
"label": "Date",
"type": "date",
"readonly": false,
"listing": true
},
{
"name": "total_calories",
"label": "Total Calories",
"type": "number",
"readonly": true,
"listing": true,
"component": "UserDailyCaloriesAndCondition"
},
{
"name": "minimun_daily_calories",
"label": "Daily Calorie Goal",
"type": "component",
"component": "UserMinimumDailyCalories",
"readonly": true,
"listing": false
},
{
"name": "observations",
"required": false,
"label": "Observations",
"type": "textarea",
"readonly": false,
"listing": true
}
],
"childComponents": [
"DailyMealIngredients"
]
}
frontend/dish_ingredients.json
Ingredientes de los platos del usuario
{
"baseUrl": "dish_ingredients",
"title": "Dish Ingredients",
"name": "Dish Ingredient",
"dbApiUrl": "dish_ingredients",
"component": "DishIngredients",
"type": "child_listing",
"subType": "array",
"array_name": "dish_ingredients",
"parentUrl": "dishes",
"endpointKeyNames": [
{
"parameterName": "dish_id",
"parentElementName": "id"
}
],
"primaryKeyName": "id",
"allow_duplicates": true,
"fieldElements": [
{
"name": "id",
"required": false,
"label": "ID",
"type": "text",
"readonly": true,
"hidden": true,
"listing": false,
"uuid_generator": true
},
{
"name": "name",
"required": true,
"label": "Name",
"readonly": false,
"listing": true,
"type": "suggestion_dropdown",
"suggestion_id_fieldname": "_id",
"suggestion_desc_fieldname": "name",
"filter_api_url": "user_ingredients",
"filter_api_request_method": "GET",
"filter_search_param_name": "name",
"filter_search_other_param": {
"like": "1",
"user_id": "{CurrentUserId}"
},
"autocomplete_fields": {
"calories_value": "calories_value",
"calories_unit": "calories_unit",
"serving_size": "serving_size",
"serving_size_unit": "serving_size_unit",
"brand_name": "brand_name",
"observations": "observations"
},
"chatbot_popup": true,
"aux_component": "ChatBotButton",
"chatbot_prompt": "Dame las %s calorías en KCAL incluyendo la cantidad de porción y la unidad de porción. Busca primero en mis ingredientes, si no está, busca con la herramienta web_search.",
"google_popup": true,
"google_prompt": "%s calorías KCAL"
},
{
"name": "calories_value",
"required": true,
"label": "Calories",
"type": "number",
"readonly": false,
"listing": true
},
{
"name": "calories_unit",
"required": true,
"label": "Calories Unit",
"type": "select",
"select_elements": "CALORIE_UNITS",
"readonly": false,
"listing": true,
"default_value": "kcal"
},
{
"name": "serving_size",
"required": true,
"label": "Serving size",
"type": "number",
"readonly": false,
"listing": true
},
{
"name": "serving_size_unit",
"required": true,
"label": "Serving size unit",
"type": "select",
"select_elements": "SERVING_SIZE_UNITS",
"readonly": false,
"listing": true,
"default_value": "g"
},
{
"name": "quantity",
"required": true,
"label": "Qty.",
"type": "number",
"min": "0",
"max": "9999",
"readonly": false,
"listing": true
},
{
"name": "total_calories",
"label": "Total",
"type": "number",
"readonly": true,
"listing": true,
"formula": "totalCaloriesCalcInDishesIngredients"
},
{
"name": "brand_name",
"required": false,
"label": "Brand Name",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "observations",
"required": false,
"label": "Observations",
"type": "textarea",
"readonly": false,
"listing": true
}
],
"dbPostWrite": [
"DishIngredientsDbPostWrite"
]
}
frontend/dishes.json
Lista de platos del usuario
{
"baseUrl": "dishes",
"title": "Dishes",
"name": "Dish",
"component": "Dishes",
"dbApiUrl": "dishes",
"mandatoryFilters": {
"user_id": "{CurrentUserId}",
"type": "D"
},
"fieldElements": [
{
"name": "id",
"required": true,
"label": "ID",
"type": "_id",
"readonly": true,
"hidden": true
},
{
"name": "user_id",
"required": true,
"label": "User ID",
"type": "text",
"readonly": true,
"hidden": true
},
{
"name": "type",
"required": true,
"label": "Type",
"type": "select",
"select_elements": "INGREDIENT_TYPE",
"readonly": true,
"hidden": false,
"default_value": "D"
},
{
"name": "name",
"required": true,
"label": "Name",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "calories_value",
"required": true,
"label": "Calories",
"type": "number",
"readonly": false,
"listing": true,
"default_value": "0"
},
{
"name": "calories_unit",
"required": true,
"label": "Calories Unit",
"type": "select",
"select_elements": "CALORIE_UNITS",
"readonly": false,
"listing": true,
"default_value": "kcal"
},
{
"name": "serving_size",
"required": true,
"label": "Serving size",
"type": "number",
"readonly": false,
"listing": true,
"default_value": "1"
},
{
"name": "serving_size_unit",
"required": true,
"label": "Serving size unit",
"type": "select",
"select_elements": "SERVING_SIZE_UNITS",
"readonly": false,
"listing": true,
"default_value": "u"
},
{
"name": "brand_name",
"required": false,
"label": "Brand Name",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "observations",
"required": false,
"label": "Observations",
"type": "textarea",
"readonly": false,
"listing": true
},
{
"name": "creation_date",
"required": true,
"label": "Created",
"type": "datetime-local",
"readonly": true,
"hidden": false,
"default_value": "current_timestamp",
"listing": true
},
{
"name": "update_date",
"required": true,
"label": "Last update",
"type": "datetime-local",
"readonly": true,
"hidden": false,
"default_value": "current_timestamp",
"listing": false
}
],
"childComponents": [
"DishIngredients"
],
"dbPreValidations": [
"UserIngredientsValidations"
]
}
frontend/food_moments.json
Tipos de comida generales (o momentos)
{
"baseUrl": "food_moments",
"title": "Food Moments",
"name": "Food Moment",
"component": "FoodMoments",
"dbApiUrl": "food_moments",
"fieldElements": [
{
"name": "id",
"required": true,
"label": "ID",
"type": "_id",
"readonly": true
},
{
"name": "name",
"required": true,
"label": "Name",
"type": "text",
"readonly": false,
"listing": true
}
],
"dbPreValidations": [
"FoodMomentsValidations"
]
}
frontend/general_config.json
Parámetros de configuración dinámica de la App
{
"baseUrl": "general_config",
"title": "Configuration Parameters",
"name": "Configuration Parameter",
"component": "GeneralConfig",
"dbApiUrl": "general_config",
"defaultOrder": "config_name|asc",
"fieldElements": [
{
"name": "id",
"required": true,
"label": "ID",
"type": "_id",
"readonly": true
},
{
"name": "config_name",
"required": true,
"label": "Name",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "active",
"required": true,
"label": "Active",
"type": "select",
"select_elements": "TRUE_FALSE",
"readonly": false,
"hidden": false,
"default_value": "1",
"listing": true
},
{
"name": "config_value",
"required": true,
"label": "Value",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "notes",
"required": true,
"label": "Notes",
"type": "text",
"readonly": false,
"listing": true
}
]
}
frontend/general_constants.json
Constantes generales de la App (verdadero/falso, sí/no, idiomas, géneros, etc.)
{
"TRUE_FALSE": {
"1": "Sí",
"0": "No"
},
"YES_NO": {
"y": "Sí",
"n": "No"
},
"LANGUAGES": {
"en": "Inglés",
"es": "Español"
},
"GENDERS": {
"m": "Masculino",
"f": "Femenino"
}
}
frontend/general_ingredients.json
Ingredientes globales
{
"baseUrl": "general_ingredients",
"title": "Ingredients (general)",
"name": "Ingredient",
"component": "GeneralIngredients",
"dbApiUrl": "general_ingredients",
"fieldElements": [
{
"name": "id",
"required": true,
"label": "ID",
"type": "_id",
"readonly": true
},
{
"name": "name",
"required": true,
"label": "Name",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "calories_value",
"required": true,
"label": "Calories",
"type": "number",
"readonly": false,
"listing": true
},
{
"name": "calories_unit",
"required": true,
"label": "Calories Unit",
"type": "select",
"select_elements": "CALORIE_UNITS",
"readonly": false,
"listing": true
},
{
"name": "serving_size",
"required": true,
"label": "Serving size",
"type": "number",
"readonly": false,
"listing": true
},
{
"name": "serving_size_unit",
"required": true,
"label": "Serving size unit",
"type": "select",
"select_elements": "SERVING_SIZE_UNITS",
"readonly": false,
"listing": true
},
{
"name": "brand_name",
"required": false,
"label": "Brand Name",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "other_names",
"required": false,
"label": "Other Names",
"type": "text",
"readonly": false,
"listing": true
}
],
"dbPreValidations": [
"GeneralIngredientsValidations"
]
}
frontend/user_ingredients_all.json
Todos los ingredientes del usuario
{
"baseUrl": "user_ingredients",
"title": "Ingredients for Suggestions",
"name": "Ingredient",
"component": "UserIngredients",
"dbApiUrl": "user_ingredients",
"mandatoryFilters": {
"user_id": "{CurrentUserId}"
},
"fieldElements": [
{
"name": "id",
"required": true,
"label": "ID",
"type": "_id",
"readonly": true,
"hidden": true
},
{
"name": "user_id",
"required": true,
"label": "User ID",
"type": "text",
"readonly": true,
"hidden": true
},
{
"name": "name",
"required": true,
"label": "Name",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "calories_value",
"required": true,
"label": "Calories",
"type": "number",
"readonly": false,
"listing": true
},
{
"name": "calories_unit",
"required": true,
"label": "Calories Unit",
"type": "select",
"select_elements": "CALORIE_UNITS",
"readonly": false,
"listing": true,
"default_value": "kcal"
},
{
"name": "serving_size",
"required": true,
"label": "Serving size",
"type": "number",
"readonly": false,
"listing": true
},
{
"name": "serving_size_unit",
"required": true,
"label": "Serving size unit",
"type": "select",
"select_elements": "SERVING_SIZE_UNITS",
"readonly": false,
"listing": true,
"default_value": "g"
},
{
"name": "brand_name",
"required": false,
"label": "Brand Name",
"type": "text",
"readonly": false,
"listing": true
}
]
}
frontend/user_ingredients.json
Ingredientes del usuario
{
"baseUrl": "user_ingredients",
"title": "Ingredients",
"name": "Ingredient",
"component": "UserIngredients",
"dbApiUrl": "user_ingredients",
"mandatoryFilters": {
"user_id": "{CurrentUserId}",
"type": "I"
},
"defaultOrder": "name",
"fieldElements": [
{
"name": "id",
"required": true,
"label": "ID",
"type": "_id",
"readonly": true,
"hidden": true
},
{
"name": "user_id",
"required": true,
"label": "User ID",
"type": "text",
"readonly": true,
"hidden": true
},
{
"name": "type",
"required": true,
"label": "Type",
"type": "select",
"select_elements": "INGREDIENT_TYPE",
"readonly": true,
"hidden": false,
"default_value": "I"
},
{
"name": "name",
"required": true,
"label": "Name",
"type": "suggestion_dropdown",
"readonly": false,
"listing": true,
"suggestion_id_fieldname": "id",
"suggestion_desc_fieldname": "description",
"suggestion_name_fieldname": "food_name",
"filter_api_url": "fda_food_query",
"filter_search_param_name": "food_name",
"filter_search_other_param": {
"autocomplete": "1"
},
"autocomplete_fields": {
"calories_value": "calories_value",
"calories_unit": "calories_unit",
"serving_size": "serving_size",
"serving_size_unit": "serving_size_unit",
"brand_name": "brand_name"
},
"chatbot_popup": true,
"aux_component": "ChatBotButton",
"chatbot_prompt": "Dame las %s calorías en KCAL incluyendo la cantidad de porción y la unidad de porción. Busca primero en la API FDA, si no está, busca con la herramienta web_search.",
"google_popup": true,
"google_prompt": "%s calorías KCAL"
},
{
"name": "calories_value",
"required": true,
"label": "Calories",
"type": "number",
"readonly": false,
"listing": true
},
{
"name": "calories_unit",
"required": true,
"label": "Calories Unit",
"type": "select",
"select_elements": "CALORIE_UNITS",
"readonly": false,
"listing": true,
"default_value": "kcal"
},
{
"name": "serving_size",
"required": true,
"label": "Serving size",
"type": "number",
"readonly": false,
"listing": true
},
{
"name": "serving_size_unit",
"required": true,
"label": "Serving size unit",
"type": "select",
"select_elements": "SERVING_SIZE_UNITS",
"readonly": false,
"listing": true,
"default_value": "g"
},
{
"name": "brand_name",
"required": false,
"label": "Brand Name",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "observations",
"required": false,
"label": "Observations",
"type": "textarea",
"readonly": false,
"listing": true
},
{
"name": "creation_date",
"required": true,
"label": "Created",
"type": "datetime-local",
"readonly": true,
"hidden": false,
"default_value": "current_timestamp",
"listing": true
},
{
"name": "update_date",
"required": true,
"label": "Last update",
"type": "datetime-local",
"readonly": true,
"hidden": false,
"default_value": "current_timestamp",
"listing": false
}
],
"dbPreValidations": [
"UserIngredientsValidations"
]
}
frontend/users_api_keys.json
Claves API del usuario
{
"baseUrl": "users_api_keys",
"title": "User API Keys",
"name": "User's API Key",
"dbApiUrl": "users_api_keys",
"component": "UsersApiKey",
"type": "child_listing",
"subType": "table",
"endpointKeyNames": [
{
"parameterName": "user_id",
"parentElementName": "id"
}
],
"primaryKeyName": "id",
"defaultOrder": "access_token",
"fieldElements": [
{
"name": "id",
"required": true,
"label": "ID",
"type": "_id",
"readonly": true
},
{
"name": "access_token",
"required": true,
"label": "Access Token",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "active",
"required": true,
"label": "Active",
"type": "select",
"select_elements": "TRUE_FALSE",
"default_value": "1",
"readonly": false,
"listing": true
}
],
"dbPreRead": [
"UsersApiKeyDbPreRead"
]
}
frontend/users_config.json
Parámetros de configuración del usuario
{
"baseUrl": "users_config",
"title": "User Configurations",
"name": "User's Configuration",
"dbApiUrl": "users_config",
"component": "UsersConfig",
"type": "child_listing",
"subType": "array",
"array_name": "users_config",
"parentUrl": "users",
"endpointKeyNames": [
{
"parameterName": "user_id",
"parentElementName": "id"
}
],
"primaryKeyName": "id",
"defaultOrder": "config_name",
"fieldElements": [
{
"name": "id",
"required": false,
"label": "ID",
"type": "text",
"readonly": true,
"hidden": true,
"listing": false,
"uuid_generator": true
},
{
"name": "config_name",
"required": true,
"label": "Name",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "config_value",
"required": true,
"label": "Value",
"type": "text",
"readonly": false,
"listing": true
}
]
}
frontend/users_food_times.json
Tiempos típicos de ingesta de comidas del usuario
{
"baseUrl": "food_times",
"title": "Food Times",
"name": "Food Time",
"dbApiUrl": "users_food_times",
"component": "UsersFoodTimes",
"type": "child_listing",
"subType": "array",
"array_name": "food_times",
"parentUrl": "users",
"endpointKeyNames": [
{
"parameterName": "user_id",
"parentElementName": "id"
}
],
"primaryKeyName": "food_moment_id",
"fieldElements": [
{
"name": "meal_type",
"label": "Type",
"required": true,
"listing": true,
"type": "suggestion_dropdown",
"suggestion_id_fieldname": "_id",
"suggestion_desc_fieldname": "name",
"filter_api_url": "food_moments",
"filter_api_request_method": "GET",
"filter_search_param_name": "name",
"filter_search_other_param": {
"like": "1"
}
},
{
"name": "meal_time",
"required": true,
"label": "Time",
"type": "text",
"readonly": false,
"listing": true
}
]
}
frontend/users_profile.json
Página de perfil del usuario
{
"baseUrl": "users",
"title": "User Profiles",
"name": "User Profile",
"component": "Users",
"dbApiUrl": "users",
"updateItem": "1",
"fieldElements": [
{
"name": "id",
"required": true,
"label": "ID",
"type": "_id",
"hidden": true,
"readonly": true
},
{
"name": "firstname",
"required": true,
"label": "First Name",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "lastname",
"required": true,
"label": "Last Name",
"type": "text",
"readonly": false,
"listing": true
},
{
"name": "email",
"required": true,
"label": "Email",
"type": "email",
"readonly": false,
"listing": true
},
{
"name": "birthday",
"required": true,
"label": "Birthday",
"type": "date",
"readonly": false
},
{
"name": "gender",
"required": true,
"label": "Gender",
"type": "select",
"select_elements": "GENDERS",
"readonly": false,
"listing": false
},
{
"name": "training_days",
"required": true,
"label": "Training Days",
"type": "text",
"readonly": false
},
{
"name": "training_hour",
"required": true,
"label": "Training Hour",
"type": "text",
"readonly": false
},
{
"name": "height",
"required": true,
"label": "Height",
"type": "number",
"readonly": false,
"listing": false
},
{
"name": "height_unit",
"required": true,
"label": "Height Unit",
"type": "select",
"select_elements": "HEIGHT_UNITS",
"readonly": false,
"listing": false
},
{
"name": "weight",
"required": true,
"label": "Weight",
"type": "number",
"readonly": false
},
{
"name": "weight_unit",
"required": true,
"label": "Weight Unit",
"type": "select",
"select_elements": "WEIGHT_UNITS",
"readonly": false
},
{
"name": "minimun_daily_calories",
"label": "Daily Calorie Goal",
"type": "component",
"component": "UserMinimumDailyCalories",
"readonly": true,
"listing": false
},
{
"name": "goal_code",
"required": true,
"label": "Goal",
"type": "select",
"select_elements": "GOAL_CODES",
"readonly": false,
"listing": false
},
{
"name": "goals",
"required": true,
"label": "Goal Observation",
"type": "textarea",
"readonly": false,
"listing": false
},
{
"name": "language",
"required": true,
"label": "Preferred Language",
"type": "select",
"select_elements": "LANGUAGES",
"readonly": false,
"listing": false
},
{
"name": "plan",
"required": true,
"label": "Billing Plan",
"type": "select",
"select_elements": "BILLING_PLANS",
"default_value": "free",
"readonly": true,
"listing": true
},
{
"name": "status",
"required": true,
"label": "Active",
"type": "select",
"select_elements": "TRUE_FALSE",
"default_value": "1",
"readonly": true
},
{
"name": "openai_api_key",
"required": false,
"label": "OpenAI API Key",
"type": "text"
},
{
"name": "openai_model",
"required": false,
"label": "OpenAI Model (defaults to gpt-4o-mini)",
"type": "text"
},
{
"name": "creation_date",
"required": true,
"label": "Client Since",
"type": "datetime-local",
"readonly": true,
"hidden": false,
"default_value": "current_timestamp",
"listing": true
},
{
"name": "label0",
"type": "hr"
},
{
"name": "label1",
"label": "PASWORD CHANGE",
"type": "label"
},
{
"name": "passcode",
"required": false,
"label": "New password",
"type": "password",
"force_value": ""
},
{
"name": "passcode_repeat",
"required": false,
"label": "Repeat new password",
"type": "password",
"force_value": ""
}
],
"childComponents": [
"UsersFoodTimes",
"UsersUserHistory",
"UsersApiKey"
],
"dbListPreRead": [
"UsersDbListPreRead"
],
"dbPreWrite": [
"UsersDbPreWrite"
],
"dbPostWrite": [
"UsersDbPostWrite"
],
"dbPreValidations": [
"UsersValidations"
],
"validations": [
"UsersPasswordValidations"
]
}