diff --git a/configs/configs.examples/calendar-enhancer.jsonc b/configs/configs.examples/calendar-enhancer.jsonc
new file mode 100644
index 0000000..b2a0df9
--- /dev/null
+++ b/configs/configs.examples/calendar-enhancer.jsonc
@@ -0,0 +1,22 @@
+{
+ // TODO:
+ "useForProjects": [
+ "Test project name 1",
+ "Test project name 2"
+ ],
+
+ // TODO:
+ "customFields": [
+ {
+ "dateFormat": "yyyy-MM-dd HH:mm",
+ "customFieldName": "Название кастомного поля 1",
+ "alias": "Название кастомного поля 1"
+ }
+ ],
+
+ "descriptionCalendarParams": {
+ "title": "Календарь:",
+ "lineRegexp": "(?<=\\*\\ ).+"
+ },
+ "calendarEventsKey": "calendar"
+}
\ No newline at end of file
diff --git a/configs/configs.examples/current-user-rules.jsonc b/configs/configs.examples/current-user-rules.jsonc
new file mode 100644
index 0000000..ac97b7c
--- /dev/null
+++ b/configs/configs.examples/current-user-rules.jsonc
@@ -0,0 +1,14 @@
+{
+ "New": "dev",
+ "In Progress": "dev",
+ "Re-opened": "dev",
+ "Code Review": "cr",
+ "Resolved": "qa",
+ "Testing": "qa",
+ "Wait Release": "dev",
+ "Pending": "dev",
+ "Feedback": "qa",
+ "Closed": "dev",
+ "Rejected": "dev",
+ "*": "dev"
+}
\ No newline at end of file
diff --git a/configs/configs.examples/eccm-config.jsonc b/configs/configs.examples/eccm-config.jsonc
new file mode 100644
index 0000000..8757829
--- /dev/null
+++ b/configs/configs.examples/eccm-config.jsonc
@@ -0,0 +1,24 @@
+// TODO:
+{
+ "currentVersions": ["1", "0.1"],
+ "projectName": "Test project name 1",
+ "currentIssuesStatuses": ["In Progress", "Re-opened", "Code Review", "Resolved", "Testing", "Feedback"],
+ "groups": [
+ {
+ "name": "Dev backend",
+ "people": [
+ "User Developer"
+ ]
+ },
+ {
+ "name": "QA",
+ "people": [
+ "Redmine Admin"
+ ]
+ }
+ ],
+ "dailyTime": {
+ "hour": 10,
+ "minute": 30
+ }
+}
\ No newline at end of file
diff --git a/configs/configs.examples/issue-event-emitter-config.jsonc b/configs/configs.examples/issue-event-emitter-config.jsonc
new file mode 100644
index 0000000..2b72666
--- /dev/null
+++ b/configs/configs.examples/issue-event-emitter-config.jsonc
@@ -0,0 +1,50 @@
+{
+
+ // "mailListener": {
+ // "issueNumberParser": "\\b(?<=#)\\d+\\b",
+ // "imapSimpleConfig": {
+ // "imap": {
+ // "user": "",
+ // "password": "",
+ // "host": "",
+ // "port": 143,
+ // // tls: true,
+ // "autotls": "always",
+ // "authTimeout": 5000
+ // }
+ // },
+ // "updateInterval": 180000, // 3 min
+ // "boxName": "INBOX"
+ // },
+
+ "rssListener": {
+ "subscriptions": [
+ {
+ "url": "https://REDMINE_HOST/projects/proj/activity.atom?key=....", // TODO
+ "issueNumberParser": "\\b(?<=#)\\d+\\b"
+ },
+ {
+ "url": "https://REDMINE_HOST/activity.atom?key=....", // TODO
+ "issueNumberParser": "\\b(?<=#)\\d+\\b"
+ }
+ ],
+ "updateInterval": 10000 // 10 sec
+ },
+
+ "issueChangesQueue": {
+ "updateInterval": 5000, // 5 sec
+ "itemsLimit": 3
+ },
+ "redmineUrlPrefix": "https://REDMINE_API_TOKEN@REDMINE_HOST", // TODO
+ "redmineUrlPublic": "https://REDMINE_HOST", // TODO
+ "webhooks": [],
+
+ "couchDb": {
+ "url": "http://admin:password@localhost:5984", // <- TODO: Указать host, port, username и password для доступа к couchdb
+ "dbs": {
+ "users": "redmine_users",
+ "issues": "redmine_issues",
+ "dashboards": "dashboards"
+ }
+ }
+}
\ No newline at end of file
diff --git a/configs/configs.examples/main-config.jsonc b/configs/configs.examples/main-config.jsonc
new file mode 100644
index 0000000..d7d9d69
--- /dev/null
+++ b/configs/configs.examples/main-config.jsonc
@@ -0,0 +1,18 @@
+{
+ "couchDb": {
+ "dbs": {
+ "changes": "redmine_changes",
+ "userMetaInfo": "user_meta_info",
+ "eccmDailyReports": "eccm_daily_reports",
+ "eccmDailyReportsUserComments": "eccm_daily_reports_user_comments"
+ }
+ },
+ "telegramBotToken": "....", // <- TODO: Указать token от бота telegram
+ "personalMessageTemplate": "{{{issue_url}}} {{{sender_name}}}:\n\n{{{message}}}",
+ "periodValidityNotification": 43200000, // 12h
+ "tagManager": {
+ "updateInterval": 15000,
+ "updateItemsLimit": 3,
+ "tagsCustomFieldName": "Tags"
+ }
+}
\ No newline at end of file
diff --git a/configs/configs.examples/redmine-status-changes-config.jsonc b/configs/configs.examples/redmine-status-changes-config.jsonc
new file mode 100644
index 0000000..0c428cc
--- /dev/null
+++ b/configs/configs.examples/redmine-status-changes-config.jsonc
@@ -0,0 +1,225 @@
+// TODO: Указать правила для формирования сообщений с уведомлениями об изменениях статусов
+[
+ {
+ "default": false,
+ "from": "New",
+ "to": "In Progress",
+ "messages": [
+ {
+ "recipient": "dev",
+ "changes_message": "{{dev.name}} взял в работу задачу #{{issue_id}}"
+ }
+ ]
+ },
+ {
+ "default": false,
+ "from": "In Progress",
+ "to": "Code Review",
+ "messages": [
+ {
+ "recipient": "dev",
+ "changes_message": "{{dev.name}} завершил разработку по задаче #{{issue_id}} и передал на ревью {{cr.name}}"
+ },
+ {
+ "recipient": "cr",
+ "changes_message": "{{cr.name}} получил задачу #{{issue_id}} на ревью от {{dev.name}}",
+ "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{issue_subject}}:\n{{dev.name}} завершил разработку по задаче и передал вам на ревью\n\n{{journal_note}}"
+ }
+ ]
+ },
+ {
+ "default": false,
+ "from": "Code Review",
+ "to": "Re-opened",
+ "messages": [
+ {
+ "recipient": "cr",
+ "changes_message": "{{cr.name}} вернул задачу #{{issue_id}} на доработку {{dev.name}}"
+ },
+ {
+ "recipient": "dev",
+ "changes_message": "{{dev.name}} получил задачу #{{issue_id}} на доработку после завершения ревью {{cr.name}}",
+ "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{cr.name}} вернул вам с ревью на доработку задачу\n\n{{journal_note}}"
+ }
+ ]
+ },
+ {
+ "default": false,
+ "from": "Re-opened",
+ "to": "In Progress",
+ "messages": [
+ {
+ "recipient": "dev",
+ "changes_message": "{{dev.name}} продолжил работу над задачей #{{issue_id}}"
+ }
+ ]
+ },
+ {
+ "default": false,
+ "from": "Code Review",
+ "to": "Resolved",
+ "messages": [
+ {
+ "recipient": "cr",
+ "changes_message": "{{cr.name}} завершил ревью задачи {{issue_id}} и передал её на тест {{qa.name}}"
+ },
+ {
+ "recipient": "qa",
+ "changes_message": "{{qa.name}} получил на тест задачу #{{issue_id}} после разработки {{dev.name}} и ревью {{cr.name}}",
+ "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{dev.name}} завершил разработку по задаче, а {{cr.name}} выполнил ревью и передали теперь вам для проверки\n\n{{journal_note}}"
+ },
+ {
+ "recipient": "dev",
+ "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{cr.name}} выполнил ревью вашей задачи и передал далее на проверку {{qa.name}}\n\n{{journal_note}}"
+ }
+ ]
+ },
+ {
+ "default": false,
+ "from": "Re-opened",
+ "to": "Code Review",
+ "messages": [
+ {
+ "recipient": "dev",
+ "changes_message": "{{dev.name}} выполнил доработки и перевёл задачу #{{issue_id}} на ревью {{cr.name}}"
+ },
+ {
+ "recipient": "cr",
+ "changes_message": "{{cr.name}} получил задачу #{{issue_id}} на повторное ревью от {{dev.name}}",
+ "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{dev.name}} выполнил по задаче доработки и теперь вы можете сделать ревью\n\n{{journal_note}}"
+ }
+ ]
+ },
+ {
+ "default": false,
+ "from": "Resolved",
+ "to": "Closed",
+ "messages": [
+ {
+ "recipient": "qa",
+ "changes_message": "{{qa.name}} протестировал задачу #{{issue_id}} и закрыл"
+ },
+ {
+ "recipient": "dev",
+ "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{qa.name}} проверил и закрыл вашу задачу"
+ }
+ ]
+ },
+ {
+ "default": false,
+ "from": "Testing",
+ "to": "Re-opened",
+ "messages": [
+ {
+ "recipient": "qa",
+ "changes_message": "{{qa.name}} вернул задачу #{{issue_id}} на доработку {{dev.name}}"
+ },
+ {
+ "recipient": "dev",
+ "changes_message": "{{dev.name}} получил от {{qa.name}} задачу #{{issue_id}} на доработку",
+ "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{qa.name}} вернул вам с тестирования задачу на доработку\n\n{{journal_note}}"
+ }
+ ]
+ },
+ {
+ "default": false,
+ "from": "Resolved",
+ "to": "Re-opened",
+ "messages": [
+ {
+ "recipient": "qa",
+ "changes_message": "{{qa.name}} вернул задачу #{{issue_id}} на доработку {{dev.name}}"
+ },
+ {
+ "recipient": "dev",
+ "changes_message": "{{dev.name}} получил от {{qa.name}} задачу #{{issue_id}} на доработку",
+ "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{qa.name}} вернул вам с тестирования задачу на доработку\n\n{{journal_note}}"
+ }
+ ]
+ },
+ {
+ "default": false,
+ "from": "Resolved",
+ "to": "Testing",
+ "messages": [
+ {
+ "recipient": "qa",
+ "changes_message": "{{qa.name}} начал проверять задачу #{{issue_id}}"
+ }
+ ]
+ },
+ {
+ "default": false,
+ "from": "Testing",
+ "to": "Closed",
+ "messages": [
+ {
+ "recipient": "qa",
+ "changes_message": "{{qa.name}} протестировал задачу #{{issue_id}} и закрыл"
+ },
+ {
+ "recipient": "dev",
+ "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{qa.name}} проверил и закрыл вашу задачу"
+ }
+ ]
+ },
+ {
+ "default": false,
+ "to": "Rejected",
+ "messages": [
+ {
+ "recipient": "initiator",
+ "changes_message": "{{initiator.name}} изменил статус задачи {{issue_id}} с {{old_status.name}} на {{new_status.name}} (dev - {{dev.name}}, cr - {{cr.name}}, qa - {{qa.name}})"
+ }
+ ]
+ },
+ {
+ "default": true,
+ "messages": [
+ {
+ "recipient": "initiator",
+ "changes_message": "{{initiator.name}} изменил статус задачи #{{issue_id}} с {{old_status.name}} на {{new_status.name}} (dev - {{dev.name}}, cr - {{cr.name}}, qa - {{qa.name}})"
+ },
+ {
+ "recipient": "dev",
+ "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{initiator.name}} изменил статус задачи с {{old_status.name}} на {{new_status.name}}"
+ },
+ {
+ "recipient": "current_user",
+ "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{initiator.name}} изменил статус задачи с {{old_status.name}} на {{new_status.name}}"
+ }
+ ]
+ },
+ {
+ "default": false,
+ "new_issue": true,
+ "from": "New",
+ "to": "New",
+ "messages": [
+ {
+ "recipient": "author",
+ "changes_message": "{{author.name}} создал новую задачу #{{issue_id}} {{#if current_user}}для {{current_user.name}}{{/if}}"
+ },
+ {
+ "recipient": "current_user",
+ "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{author.name}} создал новую задачу и назначил её на вас"
+ }
+ ]
+ },
+ {
+ "default": false,
+ "from": "Re-opened",
+ "to": "Resolved",
+ "messages": [
+ {
+ "recipient": "dev",
+ "changes_message": "{{dev.name}} перевёл задачу #{{issue_id}} на повторную проверку {{qa.name}}"
+ },
+ {
+ "recipient": "qa",
+ "changes_message": "{{qa.name}} получил задачу #{{issue_id}} на повторную проверку от {{dev.name}}",
+ "notification_message": "{{ issue_tracker }} #{{ issue_id }} {{ issue_subject }}:\n{{dev.name}} выполнил по задаче доработки и теперь вы можете проверить повторно\n\n{{journal_note}}"
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git a/configs/configs.examples/redmine-statuses-config.jsonc b/configs/configs.examples/redmine-statuses-config.jsonc
new file mode 100644
index 0000000..af3f9d2
--- /dev/null
+++ b/configs/configs.examples/redmine-statuses-config.jsonc
@@ -0,0 +1,60 @@
+// TODO: Указать какие статусы могут быть в вашем Redmine
+[
+ {
+ "id": 1,
+ "name": "New"
+ },
+ {
+ "id": 4,
+ "name": "In Progress"
+ },
+ {
+ "id": 5,
+ "name": "Re-opened"
+ },
+ {
+ "id": 6,
+ "name": "Code Review"
+ },
+ {
+ "id": 7,
+ "name": "Resolved"
+ },
+ {
+ "id": 8,
+ "name": "Testing"
+ },
+ {
+ "id": 9,
+ "name": "Wait Release"
+ },
+ {
+ "id": 10,
+ "name": "Pending"
+ },
+ {
+ "id": 11,
+ "name": "Feedback"
+ }
+
+ // {
+ // "id": 5,
+ // "name": "Closed",
+ // "is_closed": true
+ // },
+ // {
+ // "id": 6,
+ // "name": "Rejected",
+ // "is_closed": true
+ // },
+ // {
+ // "id": 7,
+ // "name": "Confirming"
+ // },
+ // {
+ // "id": 12,
+ // "name": "Frozen",
+ // "is_closed": true
+ // },
+ // ...
+]
\ No newline at end of file
diff --git a/configs/configs.examples/simple-kanban-board-config.jsonc b/configs/configs.examples/simple-kanban-board-config.jsonc
new file mode 100644
index 0000000..09676d9
--- /dev/null
+++ b/configs/configs.examples/simple-kanban-board-config.jsonc
@@ -0,0 +1,4 @@
+// deprecated
+{
+ "path": "/path/to/eltex-redmine-issue-event-emitter/configs/kanban-boards"
+}
\ No newline at end of file
diff --git a/docs/Установка.md b/docs/Установка.md
new file mode 100644
index 0000000..1419f3b
--- /dev/null
+++ b/docs/Установка.md
@@ -0,0 +1,107 @@
+# Установка
+
+Инструкция для установки приложения
+
+## Требования к системе
+
+Требования к окружению для сборки и запуска приложения:
+
+- CouchDB в качестве хранилища данных
+- NodeJS для сборки и запуска backend-а и frontend-а
+
+Доступы к внешним системам:
+
+- Токен для подключения telegram-бота
+- Токен для доступа к API Redmine
+
+## Подготовка и запуск couchdb
+
+CouchDB необходим для хранения данных.
+
+Для запуска можно воспользоваться любым удобным сопособом.
+
+Пример с помощью docker-compose
+
+1. `docker-compose.yml`:
+
+ ```yaml
+ version: '3.1'
+
+ services:
+ couchdb:
+ image: apache/couchdb:latest
+ restart: always
+ ports:
+ - 127.0.0.1:5984:5984
+ volumes:
+ - ./couchdb-data:/opt/couchdb/data
+ environment:
+ - COUCHDB_USER
+ - COUCHDB_PASSWORD
+ ```
+
+2. Так же нужно указать имя и пароль с помощью файла `.env`:
+
+ ```
+ COUCHDB_USER=admin
+ COUCHDB_PASSWORD=password
+ ```
+
+3. Создать папку `couchdb-data` для вольюма определённого для контейнера в `docker-compose.yml`:
+
+ ```shell
+ mkdir couchdb-data
+ ```
+
+4. Для запуска воспользоваться командой:
+
+ ```shell
+ docker-compose up -d
+ ```
+
+## Установка зависимостей для backend-а и frontend-а
+
+Backend и frontend написаны на языке typescript. Для загрузки и запуска необходимо выполнить:
+
+```shell
+cd $PROJECT_DIR && npm install
+cd $PROJECT_DIR/frontend && npm install
+```
+
+## Настройка
+
+Нужно скопировать все конфигурационные файлы `CONFIG_NAME.jsonc.dist` в `CONFIG_NAME.jsonc`:
+
+```shell
+cd $PROJECT_DIR/configs/
+
+cp calendar-enhancer.jsonc.dist calendar-enhancer.jsonc
+cp current-user-rules.jsonc.dist current-user-rules.jsonc
+cp eccm-config.jsonc.dist eccm-config.jsonc
+cp issue-event-emitter-config.jsonc.dist issue-event-emitter-config.jsonc
+cp main-config.jsonc.dist main-config.jsonc
+cp redmine-status-changes-config.jsonc.dist redmine-status-changes-config.jsonc
+cp redmine-statuses-config.jsonc.dist redmine-statuses-config.jsonc
+cp simple-kanban-board-config.jsonc.dist simple-kanban-board-config.jsonc
+```
+
+Или можно взять за основу файлы из папки `$PROJECT_DIR/configs/configs.example/` или в качестве примеров для заполнения. В этих файлах можно обратить внимание на строчки с TODO и рекоментациями что нужно указать в конфигурационном файле. Там могут встречаться такие рекомендации как:
+
+* Указать host, port, username и password для доступа к couchdb
+* Указать token от бота telegram
+
+## Запуск приложения
+
+1. Нужно сделать сборку frontend-а:
+
+ ```shell
+ cd $PROJECT_DIR/frontend/ && npm run build
+ ```
+
+2. Сделать сборку или можно просто запустить backend:
+
+ ```shell
+ cd $PROJECT_DIR/ && npm run start
+ ```
+
+Если нужно запустить приложение с явным указанием порта, то можно воспользоваться переменной окружения `PORT`.
\ No newline at end of file