Imagine that we need to store business contacts and track their status. It’s a typical CRM application feature. Let’s take a look at how AllcountJS framework could help us to solve this problem in 10 minutes. If you want to see the result right now - simply run the Demo

AllcountJS is an open-source rapid application development framework. It’s built on top of the MEAN (MongoDB, Express, AngularJS, NodeJS) stack. But “M” can be replaced with another database including SQL one.

Core part of AllcountJS application is a .js configuration file with mostly declarative description of application structure: entities, their fields, relations, views, roles and permissions.

All CRUD operations, default views, user management features are available out of the box.

Built-in Role Based Access Control allows to manage access rights based on user roles.

UI is generated automatically using AngularJS, Twitter Bootstrap, Jade and Font Awesome icons.

AllcountJS also provides JSON REST API to perform all operations available to users. If you need to add some specific functionality to your application you can use Dependency Injection mechanism.

Installing and Running

You can start working with AllcountJS in several ways: as a standalone application, as a dependency of another Node.js application or run a demo app at allcountjs.com.

The easiest way to see the result is just to run the application on the demo page

If you consider to deploy application on your site you should install Node.js, MongoDB and Git. Then install AllcountJS CLI by invoking an “npm install” command and perform project init:

$ npm install -g allcountjs-cli $ allcountjs init cusdevcrm-allcount $ cd cusdevcrm-allcount $ npm install

AllcountJS CLI will ask you to enter some info about your project in order to pre-fill package.json. Next, open app-config/main.js file in the application directory and replace it’s contents with following piece of code:

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" } } }, migrations: function (Migrations) { return [ { name: "statuses", operation: Migrations.insert("Status", [ {id: "1", name: "Message Sent", order: 1}, {id: "2", name: "Answered", order: 2}, {id: "3", name: "Meeting Approved", order: 3}, {id: "4", name: "Meeting Finished", order: 4}, {id: "5", name: "Rejected", order: 5} ]) }, { name: "demo-contacts", operation: Migrations.insert("Contact", [ {id: "1", name: "John Doe", company: "Acme, Inc.", email: "john@acme.com", site: "acme.com", status: {id: "1"}, lastContactDate: "2015-07-18"}, {id: "2", name: "Peter Stone", company: "FooBar LLC", email: "peter@foobar.com", status: {id: "2"}, lastContactDate: "2015-07-17"} ]) } ]} });

To run it simply invoke in cusdevcrm-allcount directory

$ allcountjs run

It’ll use your local MongoDB instance to store data so please ensure it’s up and running.

Now let’s take a look at how it works.

General application settings

The name and icon of the application are defined with the appName and appIcon properties. AllcountJS uses Font Awesome icons. You can select any icon and use it simply by referring to it’s name. When referring to the icon you need to remove fa- prefix.

appName: "CusDev CRM", appIcon: "phone",

Authentication setting configured by onlyAuthenticated property. It declares that only authenticated users may use this application.

onlyAuthenticated: true

There is also a menuItems property, but we’ll look at it after we define the entities and views.

Contacts and Statuses

Now we’re ready to describe our business entities. They’re defined in the entities property. Assume that contact will have two mandatory text fields: Name and Company, some text field with contact details, last contact date and current status.

Status field references to the status entity. Which may have values like “Message Sent”, “Answered”, “Rejected”. Status entity has name and order fields.

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" } } }

Board View

Every entity can have many views . View in AllcountJS is like SQL view: they doesn’t have special storage in database and you can operate with them like with entities. Most common use case for views is to provide custom behavior, UI and access rights.

In our case we will use views only to provide specific UI for Contact . UI template for view or entity is defined in customView property.

views: { FlowBoard: { customView: "board" } }

It refers to .jade file containing template source code. AllcountJS uses jade template engine to generate resulting HTML for web view.

There is a card board template with drag and drop feature in AllcountJS. We will use it with some customizations. So let’s create board.jade file with this piece of code:

extends project/card-board block panelBody .panel-body h4 {{item.name}} p {{item.company}} p {{item.lastContactDate | date}}

Menu

Now it’s time to describe our application menu. There is menuItems property of the app. It consists of links to application entities.

menuItems: [ { name: "Contact", entityTypeId: "Contact", icon: "user" }, { name: "Board", entityTypeId: "FlowBoard", icon: "bars" }, { name: "Statuses", entityTypeId: "Status", icon: "sort" } ]

REST API

Imagine that you have another application and want to integrate it with your new CRM. It is not a problem, because all application functions could be accessed by the REST API.

First you need to get access token. If your CRM app located at https://localhost:9080 than you need to send HTTP POST request to https://localhost:9080/api/sign-in with

{"username": "admin", "password": "admin"}

in the body. In response you will get token like this:

{"token":"56026b8ad7939dcb552a1668:PSDhU6x_VeIzqPYtIATXzEdMTLE"}

Next let’s try to get all contacts stored inside the CRM. Send HTTP GET request to https://localhost:9080/api/entity/FlowBoard or directly to https://localhost:9080/api/entity/Contact with

X-Access-Token: 56026b8ad7939dcb552a1668:PSDhU6x_VeIzqPYtIATXzEdMTLE

in header. And you will receive all your contacts in JSON. Also you can update, create, delete all your contacts thru API.

Result

We just created simple CRM app based on AllcountJS. As you can see, it was easy and didn’t take too much time:

This example shows a tiny part of possibilities of AllcountJS. Want to know more? Explore our documentation and feel free to ask on gitter.