Additional comments:

Basic authentication is the easiest to implement security to your application and it can be implemented without additional libraries. Everything needed to implement basic authentication is what you have done. The problem with basic authentication is that it is (well “basic”) and it offers the lowest security options of the common protocols. 

As far as I know there are no advanced options for using basic authentication, so you are just sending a username and password as base64 encoded. 

Basic authentication should never be used without SSL encryption because the username and password combination can be easily decoded otherwise.

The UseSession = 1 as you mentioned will break the stateless caracteristics of restfull services and you will also consume a CSP license until the session ends. 

You could take a look at other autorization frameworks as OAuth2.0, SAML (supported by Caché and Ensemble) or create your own custom protocols for access token control by using the ZAUTHENTICATE routine and Caché/Ensemble delegated access.

There are 2 nice posts from Daniel Kutac that may help you with additional options:

https://community.intersystems.com/post/cach%C3%A9-open-authorization-fr...

https://community.intersystems.com/post/cach%C3%A9-open-authorization-fr...

In order to solve  Access-Control-Allow-Origin error you can use the HandleCorsRequest feature from your rest service. 

Set class parameter HandleCorsRequest = 1 in your rest service class.

Override the OnHandleCorsRequest method in order to provide the origin domain that you want to allow  acces to your application.

https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY...

Hi Victor,

There is a customer in Brazil which is using HAProxy and KeepAlived  to set up high availability for their load balancers. They currently have 2 HAProxy servers (primary an secondary) 4 ECP servers and 1 DB server. They currently are load balancing all connections ODBC, JDBC, etc. with this solution. They are managing/load balancing approximately 5.000 user connections. I can manage to put you in contact with the customer in order to help you with some question about the architecture or configuration. 

I hope it helps.

Regards.

Fábio Gonçalves.

Hi Andrei,

As we have talked out list, it is possible to call the getContent client method in order to get data dinamically instead of using the zen mojo document stack. To do so, see the example code bellow:

ClientMethod onselect(key, value, docViewId) [ Language = javascript ]
{
console.log('select '+key);
var mainView zen(docViewId);
var realKey key.split(':')[0];
switch(realKey) {
case 'menu':
debugger;

zenPage.getContentProvider().invalidate('data','show-employee');
var obj {id:'103',level:value};
mainView.setDocumentKey('show-employee',obj);
mainView.getLayout().sourceData zenPage.getContent('data','show-employee',obj,1);
mainView.updateLayout();
break;
}
}

This example is going to manipulate de data document content on the document stack instead of adding a new document on the zen mojo document stack.

Also you can notice that the zen('mainView').currLevel will remains the same. It means that there is no new document inserted on the document stack after call getContent.

Zen Mojo is working with its all cache mechanism according to the document key which didn´t change. At this point when you call UpdateLayout Zen Mojo will just get the new document data (from getContent) and render the content (do the data binding) on the current document Layout.

Please, let me know if you have additional question about this topic.

P.S.: You can user 'force parameter' = 1 (zenPage.getContent('data','show-employee',obj,1); ) or call the invalidate (zenPage.getContentProvider().invalidate('data','show-employee'); ). According to the documentation the force parameter will clean the data before call the OnGetContent call back.

Regards.

Hi Andrei!

Although I understand your problem, I didn´t get exactely what you  want. Anyway, there is an example on SAMPLES namespace ( ZMdemo.bootstrap.HomePageServerSide.cls ) that demonstrates how to get your layout and data content from the server side. To do that yoy just to return null con getContent javascript method.

Please let me know if it helps otherwise provide additional details about what you realy expect to do.

Regards 

I agree with  Eduard Lebedyuk answer bellow that, SPA don´t work with browser back/forward buttons and consequently with the browser history. 

However, I noticed that the pushDocument has a parameter 'nohistory' that uses the mechanism  history.pushState when set as 'true'. It is available on  %ZEN.Mojo.basePage. I did some test in order to try to help Alexandre and i have noticed that after you pushDocument, popDocument, than click on back or forward browser buttons and than try to pushDocument once again, it does not work correctly as it was. 

Does anybory has any thoughts about that?

Hello Daniel,

Here in Brazil I am working with some APs and customers about the same issue. During some conversations on internal mail lists I got those inputs:

1) The first recommendation in the chain is Zen Mojo if they want to use our offering. If they have web developers they should consider HTML development with JS frameworks like AngularJS, React and connect via JSON over REST.

2) The bigger the application, the better a framework that suits more complex needs. You can build more complex systems with Zen Mojo, but after you hit a certain level of complexity it is better to leverage a less simplistic framework, like Angular or React. In general: If the customer or AP is able to build up and maintain knowledge in Angular or React, they should choose that path. If they are a Caché shop that wants to do web development, but can’t dedicate resources to it, they should choose Zen Mojo.

3) If the customer or AP decision is to use the ZEN Mojo, they can use use multiple templates for desktop applications. Multiple templates has some disadivantages.

4) We have already customers who have built complex desktop applications with Zen Mojo. Both used a generator approach, because that is what they used in their previous generation of their front-end. The Plugin Documentation is an example of a small desktop application.

5) There is some nice content related to global summit 2016 wich uses some Angular examples 

6) In general we release every 2.5 months.

I have been discussing with those AP and customers the advantages and disadivantages and also demonstrating to them in pratice how both works. The final decission should be the AP or customer decisions according to their team, busineess and strategy.

I hope it helps.

Hi Steve,

When working with multiple plugins you may have the same control type on both, in order to resolve the conflicts you can implement the "onResolvePluginConflicts" client method on your Page where you will define which is your main plugin.

Take a look bellow:

/// This event handler callack is called when more than one plugin is registered with a
/// <class>documentView</class> for the same control type.
/// 
/// In this case: $header and $control are registered both with the <class>corePlugin<class> and
/// the <class>jQMPlugin</class>
ClientMethod onResolvePluginConflicts(conflicts) [ Language = javascript ]
{
// Map all components to the jQM plugin,
// the documentView automatically checks if it's possible.
for (cmp in conflicts) {
zenThis.setPluginMapping(cmp, 'jQM');
}
}

I hope it helps.

Best regards.

Hi Alexandre,

I have tested the following and it worked as mentioned above.

Layout object:

 {type:'$containerFluid',children:[
     {type:'$dropdown',id:'dropdown',key:'drop1',buttonGroup:true,content:'Default ',children:[
         {type:'$dropdownMenuItem',content:'Action',value:'Action',key:'action'},
         {type:'$dropdownMenuItem',content:'Another action',value:'Another action',key:'another-action'},
         {type:'$dropdownMenuItem',content:'Something else here',value:'Something else here',key:'something-else-here'},
         {type:'$dropdownMenuItem',divider:true},
         {type:'$dropdownMenuItem',content:'A separated link',value:'A separated link'}
     ]},
]}

on your "onselect" javascript method you can add:

 case 'action': 
    var selText = $('#dropdownbutton').text();
    var value = mainView.getItemByKey(key).$getValue();

    $('#dropdownButton .content').html(value+' <span class="caret"></span>');
    $('#dropdownMenu').dropdown('toggle');;
    break;

Results:

Can you please try this?

Thanks.

Fábio.