(+) инициализация данных: [2023-09] при описании модуля - добавить функции-фабрики в массив Models.
В описание модели добавить seedFileName - если такое поле есть, то на этапе инициализации будет
загружены начальные данные; Также добавить поле seeds в описание
модуля - там будет массив объектов формата { modelName: string, seedFileName: string },
этот массив будет также использован на этапе инициализации
(+) изменена система инициализации приложения: [2023-09]:
- функция appBuilder создает приложение (внутри вызываем функцию exModular для инициализации части специфических свойств)
- далее инициализируем пользовательские модули
- далее appInit инициализирует приложение
- далее (при необходимости) serverBuilder делает из приложения сервер и запускает его
(!) Сделать индексы в систему - создание первичных ключей и внешних ключей. Генерация скриптов при создании баз данных, а также при загрузке данных в систему.
(?) Разобраться с ситуацией, когда необходимо свойство-ссылка на идентификатор этой же таблицы. Какой тип ставить? Если ставить id - система глючит. Может быть только один id в таблице (кстати, на это нужно проверять при старте)
(!) Система инициализации очень усложнена. Фактически для инициализации данных нужен список из имени модели и файла инициализации. Список можно собрать из module.seeds и model.seedFileName. Если сделать рефакторинг, то можно сделать поддержку moduleSet при очистке данных.
.services: мета-сервис для перечисления всех зарегистрированных сервисов в системе (например, для визуализации).storage: сервис хранения.models- глобальное пространство имён моделей.access: сервис контроля доступа.controller: сервис генерации кода контроллеров.serial: вспомогательный сервис для создания последовательности асинхронных операций (промисов).routeBuilder: сервис генерации маршрутов в формате MW для express.appBuilder: мета-сервис генерации приложения по конфигурации, заполняет справочникservices.serverBuilder: сервис генерации сервера express из текущего приложения.message: сервис уведомления о событиях, произошедших в системе.seed: сервис загрузки данных
Сервис предназначен для генерации кода клиентского приложения на основе декларативного описания приложения с сервера.
/codegen/model/:modelName: Generate code for model (template based)/codegen/model/:modelName/list: Generate code for list view of the model/codegen/model/:modelName/edit: Generate form code for edit/create views of the model/codegen/model/:modelName/filter: Generate code for filter components on the list view of the model/codegen/app/resources: генерация списка ресурсов для файлаapp.js. Как строка запроса можно передать массив из имен моделей, для которых нужно сгенерировать код примерно так:?models=MrpPlan&models=MrpProduct/codegen/app/imports: генерация списка импортов компонентов и иконок ресурсов для 'app.js'. Строковым параметром опционально передается список моделей (если нет параметра - генерируется для всех моделей)/codegen/app/models: возвращает список моделей, имеющихся в системе, в виде списка, разделенного запятыми/codegen/docs/model/:modelName: Generate docs for model/codegen/model/:modelName/field-defs: Generate field definitions for model list / edit components/codegen/model/:modelName/import-components: Generate import components code for model
Автоматически генерируемые сниппеты указаны в шаблоне файла.
(!) что еще возможно заложить во фрагменты:
- перечень модулей для импорта в зависимости от типа полей для списка, формы
- enum поля и соответствующие переменные;
- (?) сложные поля заголовков из нескольких полей;
Загрузить конфигурацию, инициализировать список сервисов.
Схема (schema): система описания структуры данных в системе, содержит в себе схему объектов, правила их инициализации и валидации. Также может содержать дополнительные обработчики событий - на языке flow.
Драйвер (driver): на основании схемы создает подключение, инициализируя его;
Подключение (connection): содержит инициализированную схему данных в виде объектов доступа - моделей.
Сервис хранения информации в системе. Работает через подключения.
Модель: это описание схемы объекта. Для каждой модели можно создать объект для доступа к данным в хранилище.
.storage.drivers: драйвера для системы хранения.storage.core: системное хранилище для моделей системы и других сервисов;.storage[connectionName: подключение к хранилищу, содержит описание подключения;.storage[connectionName].models- модели, которые существует в указанном подключении к хранилищу
Подключение (connection): *
Драйвера:
- knex-sqlite: полнофункциональный драйвер для хранения информации локально в базе SQLite
- knex-mssql: полнофункциональный драйвер для хранения в базе MSSQL Server
- json-driver: драйвер для чтения локальных ресурсов
- представить данные services через этот драйвер; на клиенте визуализировать через CardTableView;
Json драйвер работает так: создается модель внутри
Используется для создания роутов в express.
Свойства модели:
- beforeCreateBeg, beforeCreateEnd,
.afterCreateBeg,.afterCreateEnd- позволяют добавить в дополнение к стандартным обработчикам свои кастомные (например, обрабатывают пользовательский код). В данном случае на событиеCreate;
.message.mail: драйвер для сервиса уведомлений через электронную почту.message.mail.drivers: список драйверов для различных сервисов электронной почты.message.mail.system: подключение для оптавки системных уведомлений.message.mail[connectionName]: остальные подключения к различным email сервисам
Сервис предназначен для управления уведомлениями о событиях, произошедших на сервере. Сервис использует систему
контактных данных .contact о получателях уведомлений. В системе регистрируется контакты администратора, разработчика
и текущего пользователя. Также могут существовать различные иные контакты.
Система нотификации может быть расширена через пользовательские скрипты перед нотификацией или после нотификации.
Драйвера для системы сообщений:
- server log
- server console
- http webhook
- sms
- telegram
В системе указывается перечень системных получателей сообщений:
- dev: сообщения о ходе работы процедур и прочее - используется при отладке и тестировании, настраивается по каждому модулю
- admin: сообщения о работе сервера разных уровней - уведомления, ошибки и тп;
- userContacts: текущий авторизованный пользователь; этот получатель фиксируется каждый раз при работе системы авторизации;
- можно указать произвольный массив контактов, чтобы система нотификации уведомила нужного пользователя;
Работа сервиса может быть настроена в зависимости от режима работы сервера - разработка, тестирование или продакшн.
На этапе разработки/тестирования выводятся отладочные сообщения по тем блокам/модулям, которые в настоящее время отлаживаются (зависит от конфигурации).
Также в ходе работы приложения могут отправляться транзакционные уведомления - в зависимости от настроек пользователя. Пример транзакционных уведомлений - функция сброса пароля или о необходимости подтвердить аккаунт пользователя.
Параметр opt:
- where:
object: k-v pairs of field / value - whereOp:
array: [{ column, op, value }] - whereIn:
array: [{ column, ids }] - orderBy:
array: [{ column, order: 'asc/desc' }]
Модуль для регистрации простого доступа в системе
API:
- registerLoggedUser (user): зарегистрировать вошедшего в систему пользователя
- unregisterLoggedUser (user): зарегистрировать выход пользователя из системы
- addAdmin(user): добавить пользователя к группе администраторов
Модуль для авторизации посредством JWT
Auth-JWT API:
- encode (sessionId): закодировать идентификатор сессии в JWT, вернуть JWT
- getTokenFromReq (req): получить из заголовка авторизации структуру { scheme: , token: }
- check (req, res, next): миддлваре для проверки авторизации - получить токен из запроса, декодировать и проверить его, поместить в req.user.jwt, загрузить сессию в req.user.session, загрузить профиль пользователя в req.user. При ошибке продолжить с ошибкой ServerNotAllowed.
Модуль для входа в систему посредством логина и пароля
Auth-password API:
- module.login(req, res): контроллер для роута входа в систему.
- module.logout(req, res): контроллер для маршрута выхода их системы
- module.routes: определенные маршруты (/auth/login, auth/logout)
Модели в системе описываются декларативным путем.
Структура объекта, описывающего модель:
- name: имя модели
- caption: заголовок модели
- description: описание модели
- key: (только чтение) содержит название поля-идентификатора записи. В это свойство
автоматически попадает поле с типом
id - beforeSave: функция, которая будет вызвана перед записью экземпляра этой модели в БД; как параметр передается текущее значение этого экземпляра; возвращается новое значение этого экземпляра
- afterLoad: функция, которая будет вызвана после загрузки экземпляра этой модели из БД; возвращает новое значение;
- props - массив, содержит объекты-описания полей со следующей структурой:
- name: имя свойства
- type: тип свойства
- format: формат свойства (к которому приводится значение)
- default: значение поля по-умолчанию или функция, которая вызывается при необходимости сгенерировать значение поля по-умолчанию;
- caption: заголовок поля
- description: описание поля
- beforeSave: функция, которая будет вызвана перед сохранением этого поля (из методов
.createили.update); возвращает значение поля; - getter: функция, которая вызывается для этого поля если оно вычисляемое
.calculated; параметром передается весь объект, а не толлько это поле; возвращает новое значение поля; - calculated: признак того, что поле является вычисляемым;
- afterLoad: функция вызывается для поля после загрузки из БД; возвращает новое значение поля; параметром передается весь объект aItem;
Model.resourcePath: на какой маршрут монтировать
Типы свойств (prop type):
id: идентификатор записи. Такое поле может быть только одно на таблицу.array:.itemTypeуказывает тип элементов - поддерживается только(decimal, id)refs: массив ссылок на элементы, нужно ещё указать.model- на какую модель ссылаемсяref: ссылка на элемент в другой модели.modeldecimal:.precisionзнаков всего и.scaleзнаков после запятойtext: строка текста, размер можно задать свойством.size, формат задаётся свойством.format(string, date, email, name, ...)datetime: дата / время. Формат текстового представления задает свойство.format- по умолчанию этоDD-MM-YYYYboolean: логическое поле; в БД хранится как 0 и 1, а как значение свойства - false/true;enum: возмодные значения поля должны быть перечислены в поле.format
Опции отображения. Система позволяет указать опции для отображения свойства в нескольких режимах, путем добавления опций в разные объекты свойств:
- свойство
defOptions: опции по умолчанию для всех режимов отображения свойства; если опция определена для какого либо режима, то она перекроет опцию по-умолчанию; - свойство
filterOptions: позволяет указать опции для режимаfilter, в котором поле отображается в фильтре списка; - свойство
editOptions: позволяет указать опции для режимаedit, в котором поле отображается в режиме редактирования записи или создания новой записи;
Какие опции можно указывать в любом из объектов свойств:
- опция
wide: определяет ширину поля; значениеwideустанавливает 50% ширины контейнера, а значениеfullWideустанавливает 100% ширины контейнера
Пример: установить режим отображения wide по-умолчанию, а в режиме редактирования - fullWide
defOptions: {
wide: 'wide'
},
editOptions: {
wide: 'fullWidth'
}
Filter types:
- special q filter
- simple values: json object
- conditional filter: json object with suffixes for keys _lt, _lte, _gt, _gte
/route?filter=q:some%20text /route?filter={someprop: somvalue} /route?filter={someprop_gte: somevalue, someOtherProp_lt: otherValue}
flow - потоки выполнения, набор команд, которые может выполнить система. Некий аналог скрипта. Состоит из отдельных шагов.
statement (st) - отдельный шаг в потоке выполнения. Аналогичен строке кода в скрипте. Шаг может быть разных типов - или действие (action), или условным (if).
action - действие. Аналог вызова функции в скриптовых языках. Для работы с параметрами вызова, передаче результата, использования глобальных переменных используются контексты.
ctx - контекст. Контекст бывает глобальный (общий для всего потока действий), и контекст действия. Контекст действия готовится для каждого st отдельно.
API сервиса flow монтируются на appBuilder.flow:
flows:{Object}: потоки выполнения в системе, записаны под своими именами, имя - ключ в этом объектеadd(name, flow):fn: добавить указанный flow под именем name в объект flowsactions:[Array]: массив действий, определенных в системе.processAllActions():fn: метод инициализирует все действия, создает у них обязательные переменные input, output и производит импорт моделей (.models) и сервисов (.services), которые использует данное действие. На момент вызова действия гарантируется, что импорт выполнен.run(flowName, flowCtx):fn: метод для запуска действия по имени. Можно передать начальный контекст. Возвращает Promise с контекстом на момент завершения выполнения потока действий.prepareActionCtx(action, stCtx):fn: метод для подготовки контекста действияrunSt(flow, ctx):fn: выполнить шаг из потока. Номер шага должен быть указан вctx.flow.ndx
Cтандартные действия (actions):
checkDomain:- input:
email: указываем email, который нужно проверить на принадлежность к определенным доменам - env.AUTH_SIGNUP_CHECK_DOMAIN : если такая переменная установлена в false, проверка не производится. Если в true, то регистрацию пройдут только пользователи, чьи домены перечислены в ресурсе UserDomain, и для ниж установлено свойство UserDomain.isAllow в true
- input:
Сервис предназначен для загрузки данных при старте сервера. Один из этапов инициализации - это загрузка данных.
API сервиса app.exModular.services.seed:
- объект
modelSet: объект для хранения набора моделей; сюда можно добавить объекты, содержащие массивы с именами моделей, тогда можно будет загружать перечисленные модели по имени этого набора; - свойство
variantFolder{string}: для указания альтернативной папки для загрузки данных; - функция
seedModelFromFile.(modelName, fileName, opt):modelName{string}: какую модель будем инициализировать даннымиfileName{string}: имя файла для загрузки данных (см ниже)opt{Object}: опции:onlyIfEmpty: загрузка данных будет производиться только если таблица с данными пустаяupsert: выполнять загрузку данных методом обновления - добавляем отсутствующие записи, имеющиеся обновляем (записи отличаем по id)
- функция
seedAll(modelSet): загрузить все данные (или указанные в наборе)
По умолчанию, загрузка данных производится из папки SEEDS_DIR из файла .env. Существует возможность добавить
"варианты" данных путем указания имени вложенной в указанную директорию папки, для этого указываем свойство
variantFolder. Тогда система будет приоритетно
загружать данные из указанной вложенной папки варианта (если там будет нужный файл). Если нужного для модели файла в
папке варианта не будет, то система будет использовать основную папку.
Если при вызове метода указан полный путь к файлу при вызове метода .seed, то папки для загрузки (как основная, так и папка варианта) игнорируются и производится загрузка данных из указанного файла.
- примечание: метод
app.exModular.storages.Clear(modelSet)очищает все таблицы и приводит к загрузке данных заново. - Если в системе определены наборы моделей через exModular.moduleSet, то можно указать название набора
модулей в параметре вызова
app.exModular.storages.Clear(moduleSet)и будет очищен только этот набор данных
Для модуля работают следующие роуты на сервере:
/seed/variant-folders: роут возвращает перечень имеющихся на сервере вариантов данных для сидирования (список папок в папке env.SEEDS_DIR); возвращается JSON массив строк с именами папок;