Skip to content

Latest commit

 

History

History
322 lines (232 loc) · 26.3 KB

File metadata and controls

322 lines (232 loc) · 26.3 KB

exModular

Сделано

(+) инициализация данных: [2023-09] при описании модуля - добавить функции-фабрики в массив Models. В описание модели добавить seedFileName - если такое поле есть, то на этапе инициализации будет загружены начальные данные; Также добавить поле seeds в описание модуля - там будет массив объектов формата { modelName: string, seedFileName: string }, этот массив будет также использован на этапе инициализации

(+) изменена система инициализации приложения: [2023-09]:

  • функция appBuilder создает приложение (внутри вызываем функцию exModular для инициализации части специфических свойств)
  • далее инициализируем пользовательские модули
  • далее appInit инициализирует приложение
  • далее (при необходимости) serverBuilder делает из приложения сервер и запускает его

Бэклог

(!) Сделать индексы в систему - создание первичных ключей и внешних ключей. Генерация скриптов при создании баз данных, а также при загрузке данных в систему.

(?) Разобраться с ситуацией, когда необходимо свойство-ссылка на идентификатор этой же таблицы. Какой тип ставить? Если ставить id - система глючит. Может быть только один id в таблице (кстати, на это нужно проверять при старте)

(!) Система инициализации очень усложнена. Фактически для инициализации данных нужен список из имени модели и файла инициализации. Список можно собрать из module.seeds и model.seedFileName. Если сделать рефакторинг, то можно сделать поддержку moduleSet при очистке данных.

Компоненты exModular

  • .services: мета-сервис для перечисления всех зарегистрированных сервисов в системе (например, для визуализации)
  • .storage: сервис хранения
  • .models - глобальное пространство имён моделей
  • .access: сервис контроля доступа
  • .controller: сервис генерации кода контроллеров
  • .serial: вспомогательный сервис для создания последовательности асинхронных операций (промисов)
  • .routeBuilder: сервис генерации маршрутов в формате MW для express
  • .appBuilder: мета-сервис генерации приложения по конфигурации, заполняет справочник services
  • .serverBuilder: сервис генерации сервера express из текущего приложения
  • .message: сервис уведомления о событиях, произошедших в системе
  • .seed: сервис загрузки данных

Сервис codegen - генерация кода

Сервис предназначен для генерации кода клиентского приложения на основе декларативного описания приложения с сервера.

  • /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 поля и соответствующие переменные;
  • (?) сложные поля заголовков из нескольких полей;

Сервис appBuilder:

Загрузить конфигурацию, инициализировать список сервисов.

Сервис .storage

Схема (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 драйвер работает так: создается модель внутри

Сервис routeBuilder

Используется для создания роутов в express.

Свойства модели:

  • beforeCreateBeg, beforeCreateEnd, .afterCreateBeg, .afterCreateEnd - позволяют добавить в дополнение к стандартным обработчикам свои кастомные (например, обрабатывают пользовательский код). В данном случае на событие Create;

Сервис .message

  • .message.mail: драйвер для сервиса уведомлений через электронную почту
    • .message.mail.drivers: список драйверов для различных сервисов электронной почты
    • .message.mail.system: подключение для оптавки системных уведомлений
    • .message.mail[connectionName]: остальные подключения к различным email сервисам

Сервис предназначен для управления уведомлениями о событиях, произошедших на сервере. Сервис использует систему контактных данных .contact о получателях уведомлений. В системе регистрируется контакты администратора, разработчика и текущего пользователя. Также могут существовать различные иные контакты.

Система нотификации может быть расширена через пользовательские скрипты перед нотификацией или после нотификации.

Драйвера для системы сообщений:

  • server log
  • server console
  • http webhook
  • sms
  • telegram
  • email

В системе указывается перечень системных получателей сообщений:

  • dev: сообщения о ходе работы процедур и прочее - используется при отладке и тестировании, настраивается по каждому модулю
  • admin: сообщения о работе сервера разных уровней - уведомления, ошибки и тп;
  • userContacts: текущий авторизованный пользователь; этот получатель фиксируется каждый раз при работе системы авторизации;
  • можно указать произвольный массив контактов, чтобы система нотификации уведомила нужного пользователя;

Работа сервиса может быть настроена в зависимости от режима работы сервера - разработка, тестирование или продакшн.

На этапе разработки/тестирования выводятся отладочные сообщения по тем блокам/модулям, которые в настоящее время отлаживаются (зависит от конфигурации).

Также в ходе работы приложения могут отправляться транзакционные уведомления - в зависимости от настроек пользователя. Пример транзакционных уведомлений - функция сброса пароля или о необходимости подтвердить аккаунт пользователя.

Storage-knex

findAll(opt)

Параметр opt:

  • where: object: k-v pairs of field / value
  • whereOp: array: [{ column, op, value }]
  • whereIn: array: [{ column, ids }]
  • orderBy: array: [{ column, order: 'asc/desc' }]

Access-Simple

Модуль для регистрации простого доступа в системе

API:

  • registerLoggedUser (user): зарегистрировать вошедшего в систему пользователя
  • unregisterLoggedUser (user): зарегистрировать выход пользователя из системы
  • addAdmin(user): добавить пользователя к группе администраторов

Auth-JWT

Модуль для авторизации посредством 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

Модуль для входа в систему посредством логина и пароля

Auth-password API:

  • module.login(req, res): контроллер для роута входа в систему.
  • module.logout(req, res): контроллер для маршрута выхода их системы
  • module.routes: определенные маршруты (/auth/login, auth/logout)

Описание модели (Model definition)

Модели в системе описываются декларативным путем.

Структура объекта, описывающего модель:

  • 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: ссылка на элемент в другой модели .model
  • decimal: .precision знаков всего и .scale знаков после запятой
  • text: строка текста, размер можно задать свойством .size, формат задаётся свойством .format (string, date, email, name, ...)
  • datetime: дата / время. Формат текстового представления задает свойство .format - по умолчанию это DD-MM-YYYY
  • boolean: логическое поле; в БД хранится как 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

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

flow - потоки выполнения, набор команд, которые может выполнить система. Некий аналог скрипта. Состоит из отдельных шагов.

statement (st) - отдельный шаг в потоке выполнения. Аналогичен строке кода в скрипте. Шаг может быть разных типов - или действие (action), или условным (if).

action - действие. Аналог вызова функции в скриптовых языках. Для работы с параметрами вызова, передаче результата, использования глобальных переменных используются контексты.

ctx - контекст. Контекст бывает глобальный (общий для всего потока действий), и контекст действия. Контекст действия готовится для каждого st отдельно.

API сервиса flow монтируются на appBuilder.flow:

  • flows: {Object} : потоки выполнения в системе, записаны под своими именами, имя - ключ в этом объекте
  • add(name, flow): fn : добавить указанный flow под именем name в объект flows
  • actions: [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

Seed service (сервис загрузки данных)

Сервис предназначен для загрузки данных при старте сервера. Один из этапов инициализации - это загрузка данных.

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 массив строк с именами папок;