AllcountJS: Делаем простую CRM с веб-интерфейсом и REST API за 15 минут

  • Tutorial
Допустим моя компания кому-то звонит и что-то продаёт и мне нужна простая CRM, которая позволит вести справочник контактов и наглядно отслеживать их состояние в плане продажи.

Сейчас мы с вами сделаем такую систему с нуля за считанные минуты. Для этого мы будем использовать фрэймворк Allcountjs.

Самые нетерпеливые могут сразу же посмотреть на результат.



Что за AllcountJS?


Так как это первая статья на русском про AllcountJS, то скажу пару слов о самом фреймворке.
AllcountJS — это фреймворк c открытым исходным кодом для быстрой разработки веб и мобильных приложений на Node.js. AllcountJS построен на MEAN стеке (MongoDB, Express, AngularJS, NodeJS). Развивается поддержка не только MongoDB, но и других БД, в первую очередь SQL.

Центральная часть AllcountJS приложения это конфигурационный .js файл с декларативным описанием структуры приложения: сущности, отношения между ними, права доступа и т.д.

CRUD операции к сущностям, управление пользователями, настройки прав доступа, и REST API до всех функций приложения — всё это доступно сразу, без необходимости написания дополнительного кода.

Базовый веб-интерфейс приложения генерируется автоматически. Естественно его можно дорабатывать и изменять как угодно — только необходимы знания AngularJS и и языка шаблонов jade. Если возможностей фреймворка окажется недостаточно, возможно расширение функциональности через использование механизма внедрения зависимостей.

Установка и запуск


Начать работу с AllcountJS можно несколькими способами: в качестве самостоятельного приложения, как модуль другого NodeJS приложения или запустить приложение на AllcountJS.com.

Самый простой способ увидеть AllcountJS в деле — это просто запустить одно из демо-приложений в галерее.

Рассмотрим и вариант с отдельным приложением. Для этого должны быть установлены MongoDB, NodeJS и Git. (если у вас Ubuntu то вы можете посмотреть скринкаст по установке ). Для установки AllcountJS выполним:
npm install -g allcountjs-cli
allcountjs init cusdevcrm-allcount
cd cusdevcrm-allcount
npm install


Далее откройте app-config/main.js в директории с приложением и замените его содержимое следующим кодом:
A.app({
  appName: "CusDev CRM",
  appIcon: "phone",
  onlyAuthenticated: true,
  menuItems: [
    {
      name: "Contact",
      entityTypeId: "Contact",
      icon: "user"
    }, {
      name: "Board",
      entityTypeId: "FlowBoard",
      icon: "bars"
    }, {
      name: "Statuses",
      entityTypeId: "Status",
      icon: "sort"
    }
  ],
  entities: function(Fields) {
    return {
      Contact: {
        fields: {
          name: Fields.text("Name").required(),
          company: Fields.text("Company").required(),
          site: Fields.text("Site"),
          email: Fields.text("Email"),
          skype: Fields.text("Skype"),
          phone: Fields.text("Phone"),
          lastContactDate: Fields.date('Last contact date'),
          status: Fields.fixedReference("Status", "Status")
        },
        views: {
          FlowBoard: {
            customView: "board"
          }
        }
      },
      Status: {
        fields: {
          name: Fields.text("Name").required(),
          order: Fields.integer("Order").required()
        },
        sorting: [['order', 1]],
        referenceName: "name"
      }
    }
  },
});

Теперь давайте подробнее разберёмся с тем что же этот код делает.

Общие настройки приложения


Вся конфигурация приложения располагается внутри единственного метода. Название и иконка приложения задаются с помощью свойств appName и appIcon. AllcountJS использует иконки Font Awesome. Вы можете выбрать любую иконку и использовать её в приложении просто сославшись на неё по имени. При ссылке на иконку необходимо отбросить префикс fa-. Мы возьмем обычный телефонный значок для нашей «CusDev CRM».
 appName: "CusDev CRM",
 appIcon: "phone",

За настройку аутентификации отвечает свойство onlyAuthenticated. Оно определяет возможность использования приложения незарегистрированными пользователями. Мы же не хотим что бы доступ до CRM был у всех, поэтому:
onlyAuthenticated: true

Далее в конфигурации идёт пункт menuItems, но мы к нему вернёмся после того как опишем сущности и их представления.

Контакты и статусы


Теперь мы готовы к тому что бы описать наши бизнес-сущности.
Опишем сущность Contact. Пусть у контакта будут два обязательных текстовых поля — Name и Company. Несколько текстовых полей с информацией о способах связи, дата последнего контакта и текущий статус контакта.
Поле status — это ссылка на сущность статус в которых может находиться контакт (например “Написали”, “Ответил”, “Готов на встречу”).
entities: function(Fields) {
    return {
      Contact: {   
        fields: {    
          name: Fields.text("Name").required(),    
          company: Fields.text("Company").required(),    
          site: Fields.text("Site"),   
          email: Fields.text("Email"),   
          skype: Fields.text("Skype"),    
          phone: Fields.text("Phone"),
          lastContactDate: Fields.date('Last contact date'),    
          status: Fields.fixedReference("Status", "Status")    
        }
      },    
      Status: {    
        fields: {    
          name: Fields.text("Name").required(),   
          order: Fields.integer("Order").required()    
        },    
        sorting: [['order', 1]],    
        referenceName: "name"    
      }    
    }   
  }


Отображение на доске


Каждая сущность может иметь представления (вью). Они задаются в свойстве view. Представления в AllcountJS похожи на представления в SQL. Они не занимают дополнительного места в БД, но вы можете работать с ними как с обычными сущностями. Представления можно использовать для того что бы обеспечить специальное поведение, интерфейс и права доступа.

В нашем случае мы будем использовать представления для того что бы сделать специальный UI в виде интерактивной доски для отображения контактов. Зададим для контакта представление FlowBoard а внутри него, в свойстве customView, UI шаблон board.
views: {    
  FlowBoard: {    
    customView: "board"   
  }   
}

Он ссылается на .jade файл, содержащий код шаблона. AllcountJS использует шаблонизатор jade для генерации конечного HTML для веб интерфейсов. Подробнее о jade можно прочитать на jade-lang.com
В комплекте AllcountJS есть шаблон канбан доски с драг-анд-дропом. Наше представление board является его расширением. Создадим файл board.jade со следующим кодом внутри:
extends project/card-board    
block panelBody    
  .panel-body    
    h4 {{item.name}}    
    p {{item.company}}    
    p {{item.lastContactDate | date}} 



Меню


Теперь мы дошли и до меню нашего приложения. Оно задаётся в свойстве menuItems и состоит из ссылок на сущности и представления.
menuItems: [    
    {    
      name: "Contact",    
      entityTypeId: "Contact",    
      icon: "user"    
    }, {    
      name: "Board",    
      entityTypeId: "FlowBoard",    
      icon: "bars"    
    }, {    
      name: "Statuses",    
      entityTypeId: "Status",    
      icon: "sort"    
    }    
  ]


REST API


Если у нас есть какое-нибудь другое приложение, которое нужно интегрировать с нашей CRM, то это не будет проблемой, т.к. все функции приложения доступны через REST API.

Для начала нужно получить токен для доступа. Допустим наша CRM располагается на https://localhost:9080, в таком случае необходимо отправить HTTP POST запрос на
https://localhost:9080/api/sign-in
С таким JSON содержимым в теле:
{"username": "admin", "password": "admin"}

В ответ вернётся примерно такой ответ:
{"token":"56026b8ad7939dcb552a1668:PSDhU6x_VeIzqPYtIATXzEdMTLE"}

Теперь можно, например, получить список всех контактов. Для этого отправим HTTP GET запрос, но уже с заголовком
X-Access-Token в который передадим полученный токен из предыдущего запроса.
На https://localhost:9080/api/entity/FlowBoard
или напрямую на https://localhost:9080/api/entity/Contact
В ответ вы получите список всех контактов в формате JSON. Естественно что вы можете также удалять, создавать и обновлять ваши контакты через API.

AllcountJS может больше


В статье, на примере простой CRM показана лишь малая часть возможностей AllcountJS. В демо-приложении кроме выше рассмотренного есть ещё и русская локализация, которую можно отключить вписав forcelocale: «en» в раздел с общими настройками. А завершает конфигурацию скрипт по добавлению тестовых данных.

В следующих статьях мы продолжим знакомить вас с устройством и возможностями фреймворка. В следующей статье мы покажем как можно сделать и мобильное приложение к нашей CRM. Тоже достаточно быстро. Кому не терпится узнать больше и кого не пугает английский — добро пожаловать на официальный сайт allcountjs.com.
AllcountJS
15,86
Компания
Поделиться публикацией

Комментарии 21

    0
    Для начала нужно получить токен для доступа. [...] необходимо отправить HTTP POST[...] c таким JSON содержимым в теле:

    Ауч, почему очередной велосипед вместо OAuth?
      0
      lair, спасибо за вопрос!
      Если коротко, то мы поддерживаем пока только JWT-like подход авторизации API для клиентов, которые владеют паролем напрямую. Например, это используется для мобильных приложений. OAuth для поддержки авторизации третьих сторон в планах. Подробнее про разницу подходов можно почитать здесь: www.seedbox.com/en/blog/2015/06/05/oauth-2-vs-json-web-tokens-comment-securiser-un-api
        0
        Так в OAuth 2 это тоже есть, называется client credentials flow. Зачем велосипед?
          0
          lair, Вы действительно правы. OAuth 2 полностью поддерживает этот сценарий. Когда мы внедрим OAuth, он вероятно станет нашим основным механизмом авторизации. На момент разработки текущего механизма стояла задача обеспечить авторизацию только между двумя сторонами. JWT подход решает эту задачу. OAuth 2 также ее решает, но он сложнее в реализации. JWT подход был выбран из-за простоты и скорости разработки.
            0
            OAuth 2 также ее решает, но он сложнее в реализации.

            Вы хотите сказать, что для node.js нет готовых решений?
              +1
              Сергей, хочу сказать решения есть. Вот например: github.com/thomseddon/node-oauth2-server. Но для того, чтобы его использовать, нужно как минимум решить проблему с хранением токенов. Мы поддерживаем как MongoDB так и базы данных SQL. Поэтому здесь задача немного усложняется. Т.е. это делается, но на это нужно было бы потратить немного больше времени, чем на JWT. Мы приветствуем любые инициативы относительно развития проекта. Их можно писать прямо сюда: github.com/allcount/allcountjs/issues. Если Вы знаете как можно быстро и просто реализовать OAuth 2, то мы с удовольствием примем от Вас pull request.
      0
      [mr.accuracy]На сайте написано, что за 10 минут. ;)[/mr.accuracy]
      Заинтересовало, в качестве автогенератора апи для мобильных приложений.
        0
        jMas, спасибо за обратную связь!
        Вы нас поймали! :) Я думаю Максим поделится своими соображениями, где возникает разница на 5 минут.
        Рады, что смогли Вас заинтересовать! Для гибридных мобильных приложений у нас также есть интеграция с ionic (http://ionicframework.com/). Если есть вопросы, то мы доступны в чате Gitter: gitter.im/allcount/allcountjs, в группе facebook: www.facebook.com/groups/allcountjs и здесь.
          0
          Англоговорящие поймут быстрее, и за 15 все успеют)
          0
          Хмм… А вот на Orienteer можно и вообще за 5 минут такое сделать причем вообще не кодируя. Но тема да — интересная… Какие есть ограничения у фреймворка? Т.е. какие задачи гарантировано не стали бы решать AllCountsJS?
            0
            DbLogs, здорово! Спасибо за ссылку!
            Не рекомендую использовать AllcountJS, где нет работы с БД, т.к. его использование становится бессмысленным. AllcountJS заточен на то, чтобы сделать разработку всего, что связано с CRUD максимально простым не ограничивая возможности эко-системы Node.js. Любые бизнес приложения (CRM например) это по сути своей в основном CRUD и AllcountJS для этого хорошо подходит.
            Также мы постараемся раскрыть в ближайших публикациях как применить AllcountJS к продуктовым историям, где есть backoffice. Например, на днях мы запустили zrum.ru — поисковик по наличию мотозапчастей, на который потратили 6 часов работы. Там внутренняя БД запчастей синхронизируется с внешними excel файлами, которые лежат в открытом доступе по URL. При этом из коробки есть возможность вести каталог вручную.
              0
              Двойственные впечатления, с одной стороны — довольно любопытно. Хотелось бы так же взглянуть на roadmap и узнать планы монетизации. С другой стороны — лично меня angular смущает, мне нравятся библиотеки попроще. Более того, я не уверен, что вы с ангуляром всё делаете правильно, т.к. на вашем же allcountjs.com (который, как я прочёл, написан с использованием самого себя) вижу пару мест где во время загрузки показываются знаменитые {{...}}
                0
                Это можно полечить с помощью docs.angularjs.org/api/ng/directive/ngCloak, но ИМХО это не критичный «недочет», если использовать систему в качестве админки, пользователи все равно ничего не увидят.
                  +1
                  yurash, спасибо за обратную связь!
                  Основной план по монетизации пока хостинг и on-premise DevOps решения. Мы используем CoreOS + Docker инфраструктуру для изолированного запуска приложений. Именно она используется для запуска демонстраций.
                  По roadmap основные направления выглядят на данный момент так:
                  — Интеграции и двусторонний обмен данными с наиболее популярными сервисами (Почта, файловые хранилища, социальные сети, SIP, SMS, Платежные системы и т.д.)
                  — Поддержка наиболее популярных SQL БД (MySQL, MSSQL, Oracle, и т.д.). Сейчас есть Postgres.
                  — Поддержка различных библиотек представления и выделение angular представления в отдельный модуль. Пока кандидаты на реализацию: React и ReactNative для мобильных устройств. Будем рады услышать здесь дополнительные предложения по реализации.

                  Насчет angular: спасибо за бдительность! Там действительно не хватало ng-cloak. Это хак, который прячет нутро angular. Исправили. Что касается сложности/простоты angular: у него есть свои плюсы и минусы. Мы его взяли за основу, т.к. он на данный момент самый популярный JS MVC framework. Но мы на него не завязаны и строим AllcountJS не зависимым от представления. Здесь примем любую помощь в создании AllcountJS frontend'а с помощью других framework'ов!
                    0
                    Павел, а где непосредственно CoreOS запускаете? DO? Или что-то свое? Используете какое-нибудь сущетсвующее решение для «заказа» запуска нового докера?
                      0
                      DbLogs, сейчас используем DigitalOcean. Но мы не привязаны к хостингу и планируем разворачивать свою инфраструктуру там, где будет требоваться заказчику. В том числе и в частных облаках как on-premise решение.
                      Для запуска Docker контейнеров используем github.com/coreos/fleet.
                        0
                        Если не секрет, то как решаете вопрос с персистентностью контейнеров? Или пока с этим не заморачивались и нода «стирается», ну или контейнер привязыватеся к той или иной ноде?
                          0
                          DbLogs, не секрет. Никак не решаем. Контейнер уже содержит, все что необходимо для запуска приложения почти также как это сделано в Heroku.
                            0
                            В том то и дело, что хероку при перезапуске все что пользователь «наделал» стирается полностью. Там если нужна персистентность, то надо использовать внешние ресурсы. А мы в Orienteer, естественно, хотели бы, чтобы при остановке ноды данные пользователя не пропадали. В docker есть volume фишка, но когда у тебя облако, то возникает проблема переноса volume на другую ноду по необходимости. Обычно люди через ZFS решают, но хотелось бы что-нибудь из коробки…
                              0
                              DbLogs, проблема с переносом данных в облаке действительно сложная. Поэтому мы также как и Heroku используем БД или внешние сервисы для хранения данных.
                  0
                  Шикарно! Спасибо большое за статью!

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое