Portal Installation Guide

© 2022 MonkeyProof Solutions BV



T: +31 (0)76 8200 314

Table of contents

Portal Installation Guide

Table of contents

NGINX configuration

PHP configuration

Apache .htaccess



The Portal Server v0.2.0 is an application written in PHP 8.

The Portal Server has the following main tasks:

  1. Web based Admin Portal for:
    • Configuring deployed applications
    • Managing application access
    • Managing available front-end versions
    • Providing log access
  2. Web based User Portal for:
    • Listing the authorized applications and relevant information
  3. Deliver "static" content (the generic frontend application versions) to the client browser
  4. Manage user sessions including:
    • Authentication/authorization
    • Mapping of application instances to the appropriate back-end endpoints
    • Data flow

Configurations are stored in a json file and, if applicable, configuration/application specific data in additional supporting files.

No SQL database is required.

System Requirements

This paragraph provides some guidance in server hard- and software requirements.

The server does not need to be a high performance computing server, the back-end server(s) do the hard computational work.

Depending on the type of deployed applications, the dataflow can be significant and needs to be managed in-memory.

The duration of computations and the number of simultaneous users need to be accomodated. If there are many users doing many long-running computations, the server resources (memory) and number of simultaneous PHP processes need to be scaled up accordingly.

Server Hardware Requirements

Server type

The server can be a metal, virtualized. containerized or even "serverless" web- or app-server, that supports PHP 8.

CPU and Memory

As for any web application, you should size your server based on the traffic on the site.

Typically analytics applications deployed through the Portal Server are quite data intensive. During interaction with the server all data, including file up- and downloads, lives in memory in the Portal Server.

It is recommended to assign 512MB per simultaneous active server request. If applications do not do significant file up- and download this can be reduced.


The Portal Server application code is less than 50MB.

The main driving factors behind required additional disk space are:

  1. The amount of front-end versions to be supported (current production versions < 10M each).
  2. Logging enabled in combination with traffic through the server.

Logging directory can be configured outside the installation directory (recommended).

Particularly when traffic logging (intended for debugging purposes only) is enabled for an application log files can grow rapidly. File up- and download data is never being logged to save space.

Apart from disk space for logging it is recommended to allocate at least 1GB of diskspace for the application itself.

Server Software Requirements

Operating System

The Portal Server runs on Windows, and Linux (and most likely on other plaforms supporting webserver and PHP 8 technology).

Web Server

The Portal Server has been developed and tested with NGINX and Apache. Most likely it will work with any recent web server software with PHP 8 support.


The web server must support PHP 8. It can be installed as CGI or any other integration technology.

PHP extensions

The development and testing of the Portal Server has been done by means of a standard binairy PHP build including the standard range of extensions.

Next to those extensions the below are required to be enabled in the php.ini file of your server.

Mandatory extensions:

curlrequired for communication between the Portal Server and the MATLAB/Python backend servers
fileinfogeneral purpose
ldaprequired for LDAP or Active Directory authentication
opensslrequired for HTTPS communication between Portal Server and MATLAB/Python backend servers
zlibrequired to enable output compression

Please refer to the Installation paragraph where the check.php script is dicussed for highlighting permissions and lsting of values of som key settings. The location of the php.ini file used is also listed in the check.php results.

PHP.INI settings

PHP SettingSuggested ValueComment
max_execution_time300Excludes the time required for the curl call to the backend. Curl timeout is configured per application.
memory_limit512MThis limit should be sufficiently large (e.g. 4x the maximum expected payload incl. file uploads).
post_max_size256MThis limit should be sufficiently large (e.g. 2x the maximum expected payload incl. file uploads).

Please refer to the PHP documentation for more information.

Note that your webserver settings may be more restrictive than the PHP settings listed here.

Client Requirements

The Portal Server should run on all recent browsers in the market, including but not limited to:

  • Chrome
  • Firefox
  • Edge
  • Safari

Development and testing is primarily being done with Chrome and Firefox (in that order).


These tasks cover the download and deployment of the Portal Server, and should be performed prior to any new installation or upgrade.

  1. Download Portal Server per instructions received per email.

  2. Transfer the downloaded file to your webserver.

  3. Extract the release. The extraction process should create a new directory webserver, in the remainder of this document this will be referred to as the <INSTALL_ROOT>.

  4. The <INSTALL_ROOT>/public directory is the root of the web application. The other directories at this level only need to be accessed by PHP itself and should not be directly served by the webserver.

  5. All routes that do not refer to an existing file or directory in or under the <INSTALL_ROOT>/public/ directory need to be routed through <INSTALL_ROOT>/public/index.php. A sample nginx configuration and a sample (apache) .htaccess file are included as appendices. These are starting points, the same routing result can be achieved in different ways.

  6. Documentation can be found under <INSTALL_ROOT>/public/doc. Index index.php needs to be served at this top level. It is advisable to serve index.html for sub directories. This can be accomplished in your webserver configuration or by means of .htaccess file(s).

New Installation

This chapter explains how to perform a new installation of Portal Server.

Start by checking “System Requirements” and the "Pre-Installation tasks".

When the webserver with PHP 8 is up and running with <INSTALL_ROOT>/public as root, move or copy the <INSTALL_ROOT>/check.php file to <INSTALL_ROOT>/public/check.php.

From your web browser, access https://yoursite/check.php and inspect the results and see if to see if there are obvious missing requirements.

When done either delete or move the script file back to <INSTALL_ROOT>/check.php to prevent direct access or execution by unauthorized users.


Next step is to configure the Portal Server by creating the <INSTALL_ROOT>/config/config.php.

Copy <INSTALL_ROOT>/config/config.php.sample to <INSTALL_ROOT>/config/config.php and open it in your favorite editor.

NOTE: Keep the trailing DIRECTORY_SEPARATOR intact when editing paths.

Main Portal Settings

The $portal['title'] (string), $portal['subtitle'] (string) and $portal['logo'] (string: system path to file) are used in the header of the user- and admin-portals as well as in the login box.

The $portal['debug'] (boolean) setting indicates if additional debugging info may be shown. The $portal['debug_error_reporting'] and $portal['debug_ini_set_display_errors'] settings refer to values per standard PHP debugging levels.

Please refer to PHP documentation https://www.php.net/manual/en/function.error-reporting.php and https://www.php.net/manual/en/errorfunc.configuration.php#ini.display-errors for more details.

Enabling debugging can provide additional information to track down issues but is recomended to disable for regular use. Due to unpredictable behaviour it may break functionality of the portal. Inspecting error logs is a better starting point to identify issues.

The $portal['https'] setting allows for telling PHP that the portal is served over https. By default it is attempted to detect if the application is served over https but PHP cannot always correctly determine this due to webservers not setting values per the standard. This setting will make it explicit.

$portal['title']                          = '';
$portal['subtitle']                       = '';
$portal['logo']                           = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'monkeyproof.png';

$portal['debug']                          = false;
$portal['debug_error_reporting']          = 'E_ERROR';
$portal['debug_ini_set_display_errors']   = '1';

//true if serving over https, false if not, null to ignore this setting. 
//(This is an "override" if $_SERVER['HTTPS'] is not available on server or contains a value if not serving over https).
$portal['https']                          = null; 


The $logging['dir'] (string) contains the path to the top level logging directory. The default value included writes logs into the installation directory is not preferred for production environments. You can set any location with write permission for the php/webserver user here.

The $logging['log_rotate_enabled'] (boolean) setting enables or disables log rotation. When enabled log files are rotated on a daily basis (when there is activity). The $logging['log_rotate_keep'][*] (number) settings allow for setting the number of logs to keep for each log type. To keep rotated logs forever set to 0. Note that traffic logs are intended for debugging issues and can grow rapidly.

$logging['dir']                           = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR;
// enable daily log rotate
$logging['log_rotate_enabled']            = true;
//number of rotated log files to keep (i.e. the last x days of activity on the portal)
//0 means all are kept
$logging['log_rotate_keep']['access']     = 0; 
$logging['log_rotate_keep']['error']      = 30; 
$logging['log_rotate_keep']['traffic']    = 5; 


The portal currently supports four authentication modes that can be selected by setting $auth['type']. The four modes are:

  1. 'anonymous': Anonymous mode allows users to use the portal and applications without authentication. When a session expires it cannot be restored and data may be lost.

NOTE: Anonymous mode should only be used for testing purposes during installation. It should NOT be used in production.

  1. 'managed': Basic user management included in the portal. See Managed.
  2. 'ldap': Authentication against Microsoft Active Directory. See LDAP.
  3. 'azure_ad': Authentication against Azure Active Directory. See Azure AD.

The $auth['debug'] (boolean) should be set to false in production but setting it to true may help during configuration. Also inspect the access and error logs when running into issues during configuration.

$auth['type']                             = 'managed';
$auth['debug']                            = false;


The managed mode provides basic stand-alone user management in the admin portal. Users can be created, added to groups in the admin portal and can be invited via email.

In order to send the invitation emails, PHPMailer must be configured in mail_config.php.

use PHPMailer\PHPMailer\PHPMailer;

$mail = new PHPMailer;

$mail->SMTPDebug = 0;
$mail->Debugoutput = 'html';
$mail->Host = "smtp.example.com";
$mail->Port = 25;
$mail->SMTPAuth = false;
$mail->SMTPAutoTLS = false;
$mail->SMTPSecure = false;
$mail->setFrom('simian-suite@example.com', 'Simian Suite');

In order to create the administrator account, copy <INSTALL_ROOT>/src/auth/managed/reset_admin_password.php to <INSTALL_ROOT>/public/. Then, in the browser navigate to https://yoursite/reset_admin_password.php. After specifying the password, it will be possible to log in as user admin.

Note: Do not forget to remove the file from the public folder afterwards!


The Portal Server can be configured to authenticate against Microsoft Active Directory. LDAP integration is enabled by setting the $auth['type'] to 'ldap'.

The $ldapconfig['start_tls'] setting enables TLS for secure communication with the LDAP server.

The connection with the LDAP server is set up using the standard PHP LDAP plugin and can further be configured in $ldapconfig['ldap_options'] (array) by means of an array of the LDAP_OPT_* settings. More information can be found here https://www.php.net/manual/en/ldap.constants.php. Noteworthy is the 'LDAP_OPT_X_TLS_CACERTFILE' option which contains the path to the Certificate Authority Certificat file such that the certificate of the LDAP server can ve validated.

The $ldapconfig['host'] (string) and $ldapconfig['port'] (string) setting indicate on which address and port the LDAP server can be contacted.

The $ldapconfig['domain'] (string) is your microsoft domain name. The $ldapconfig['basedn'] (string) is the top level from where searches are being done in the LDAP server.

The $ldapconfig['usersdn'] (string) is the distinguished name where searches will be exected for users (note that we reuse/concatenate the $ldapconfig['usersdn'] setting). The $ldapconfig['user_name_attribute'] (string) is the user attribute containing the name used for authentication (for MS AD this is 'sAMAccountName'). The $ldapconfig['user_photo_attribute'] (string) and $ldapconfig['user_displayname_attribute'] (string) contain the attributes containing the user display name and photo respectively.

The $ldapconfig['groupsdn'] (string) is the distinguished name where searches for security groups will be executed. The $ldapconfig['gropup_name_attribute'] (string) is the attribute being searched for to identify user membership (for MS AD this is 'sAMAccountName').

The LDAP integration oly uses user credentials for authentication. All other communication for e.g. retrieval of user details and querying group membership happens with a read-only LDAP user with username $ldapconfig['readonly_user'] (string) and password $ldapconfig['readonly_pw'] (string).

Direct subgroups of $ldapconfig['portal_parent_groups'] (array of strings) will be selectable in applications configurations in the admin portal. Leave unspecified to show all groups. Access to the user portal requires membership of any of the groups listed in $ldapconfig['portal_user_groups'] (array of strings). Use empty array [] to not require portal user group membership (authentication is then still required). Access to the Admin Portal requires membership of any of the groups listed in $ldapconfig['portal_admin_groups'] (array of strings).

$ldapconfig['start_tls']                  = true;

// LDAP Options - see: https://www.php.net/manual/en/ldap.constants.php
$ldapconfig['ldap_options']               = array(
    'LDAP_OPT_X_TLS_CACERTFILE'           => 'path_to_cacert.crt',
    // 'LDAP_OPT_X_TLS_CACERTDIR'            => '',
    // 'LDAP_OPT_X_TLS_CERTFILE'             => '',
    // 'LDAP_OPT_X_TLS_KEYFILE'              => '',
    'LDAP_OPT_PROTOCOL_VERSION'           => 3,
    'LDAP_OPT_REFERRALS'                  => 0,
    'LDAP_OPT_NETWORK_TIMEOUT'            => 10,

$ldapconfig['host']                       = 'your.ldap.server';
$ldapconfig['port']                       = '389';

$ldapconfig['domain']                     = 'your_domain';
$ldapconfig['basedn']                     = 'dc=your,dc=domain';

$ldapconfig['usersdn']                    = 'cn=Users,' . $ldapconfig['basedn'];
$ldapconfig['user_name_attribute']        = 'sAMAccountName';
$ldapconfig['user_photo_attribute']       = 'thumbnailphoto';
$ldapconfig['user_displayname_attribute'] = 'displayname';

$ldapconfig['groupsdn']                   = 'cn=Groups,' . $ldapconfig['basedn'];
$ldapconfig['group_name_attribute']       = 'sAMAccountName';

// saMAccountName and password of (read-only) LDAP query user
$ldapconfig['readonly_user']              = '';
$ldapconfig['readonly_pw']                = '';	

$ldapconfig['portal_parent_groups']       = ['CN=your_parent_group,CN=Users,DC=example,DC=com'];
$ldapconfig['portal_user_groups']         = ['CN=group_name,CN=Groups,DC=example,DC=com'];
$ldapconfig['portal_admin_groups']        = ['CN=group_name,CN=Groups,DC=example,DC=com'];

Azure AD

The Azure AD authorization mode allows users to authenticate using their Microsoft Azure AD account. When the user is already signed in, the authorization happens without user interaction. After successful authorization, the user can sign out of (or stay signed in on) the portal independently from the Microsoft Azure AD account.

The Portal Server can be configured to authenticate against Azure Active Directory. Azure integration is enabled by setting the $auth['type'] to 'azure_ad'.

The $azure_ad_config['ad_tenant'] (string) is the Azure Active Directory Tenant ID. With Multitenant apps you can use "common" as Tenant ID, but using specific endpoint is recommended when possible.

The $azure_ad_config['client_id'] (string) is the client application ID provided by Azure.

The $azure_ad_config['client_secret'] (string) is the Client Secret provided by Azure. Remember that this expires someday unless you haven't set it not to do so.

The $azure_ad_config['portal_admin_groups'] (array of strings) are the user group IDs that will be granted access to the admin portal.

The $azure_ad_config['portal_parent_groups'] (array of strings) are user group IDs of which direct member groups will be listed for selection in the admin portal to grant users access to individual applications.

// Azure AD Options
$azure_ad_config['ad_tenant']               = "ea4656af-8f49-46cd-b355-fef4d8735127";
$azure_ad_config['client_id']               = "54d7c310-9afa-4e9a-9717-d934f64f4161";
$azure_ad_config['client_secret']           = "PmcZIvH0kxA8W9IECyymu6ZzjEy+MbAvXqDHFe3G";
$azure_ad_config['portal_admin_groups']     = ["f2884a1c-62e8-425c-b32a-25881f375823"];
$azure_ad_config['portal_parent_groups']    = ["ea2d7058-a486-46c5-bc4b-7c7fc14db767"];
// END Azure AD

Landing pages

When the Portal Server has been configured appropriately, the following pages are available:

https://yoursite/The user portal listing available applications.
https://yoursite/admin_portal/The admin portal for cinfiguring applications.
https://yoursite/check.phpWARNING: This file should be removed or renamed after installation.



Prior to upgrading the webserver, it is strongly recommended to notify the users about the scheduled maintenance and urge them to close their sessions. All sessions will be removed during the upgrade.

  1. Prevent user interaction (if possible) - starting in v1.5.0 Maintenance mode can be used for this purpose
  2. Verify that there are no busy instances (no *.busy in the userSessionData) - starting in v1.5.0 Instances management can be used for this purpose
  3. Stop the webserver
  4. Remove the contents of the userSessionData directory

Note It is preferred that users close their sessions, such that cleanup actions are performed. The instances management handles this correctly, but when user session folders are deleted manually, artifacts may remain on the back-end server(s).

Upgrade webserver

  1. Rename the old installation
  2. Unzip the new webserver version in the same location
  3. Copy configuration files from the old installation to the new one
    • config.php
    • configurations.json
    • users.json (in case of managed authentication)
    • mail_config.php (in case of managed authentication)
  4. Update config.php as described in the next section
  5. Start the webserver
  6. Verify correct settings in php.ini using check.php

Configuration changes

In the webserver v0.4.0 release, some configuration settings have been subject to change with respect to older releases.


if (!defined('BASE_URL')) {if (!defined('INDEX_TOKEN')) {
$auth['disabled']No longer exists
$auth['user_password']No longer exists
$auth['type']'anonymous', 'azure_ad', 'ldap' or 'managed'
LDAP config replaced bare group names group_namewith full distinguished names CN=group_name,CN=Groups,DC=example,DC=com


LDAP config replaced bare group names group_namewith full distinguished names CN=group_name,CN=Groups,DC=example,DC=com

NGINX configuration

The below is a sample nginx.conf configuration from a working NGIX installation with fastcgi PHP support.

It is intended as inspiration/starting point for your configuration - as-is and by no means as a final, complete configuration.

#user  nobody;
worker_processes  4;

error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

events {
    worker_connections  1024;

http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  2700;

	gzip on;
	gzip_vary on;
	gzip_min_length 1024;
	gzip_proxied expired no-cache no-store private auth;
	gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/javascript application/xml application/json;
	gzip_disable "MSIE [1-6]\.";

	fastcgi_connect_timeout 2700s;
	fastcgi_keep_conn off;
	fastcgi_read_timeout 2700s;
	fastcgi_send_timeout 2700s;

	client_max_body_size 256m;

	server {
		   listen         80;
		   server_name    <YOUR_SERVER_FQDN>;
		   return         301 https://$server_name$request_uri;

    # HTTPS server
    server {
        listen       443 ssl;
        server_name  localhost;

        ssl_certificate      <SYSTEM_PATH_TO_THE_SERVER_CERTIFICATED DIRECTORY>/your_server-cert.crt;
        ssl_certificate_key  <SYSTEM_PATH_TO_THE_SERVER_CERTIFICATED DIRECTORY>/your_server-private-key.pem;

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;

        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on;

        root   <SYSTEM_PATH_TO_THE_SERVER_INSTALL>/public;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        # cache static frontend version content "forever" (rather one year) 
        location ~* ^/apps/browser-v[0-9\.]+(\-rc\d+)?-prod/.+\.(js|css|jpg|jpeg|png|gif|js|css|ico|swf|woff|woff2)$ {
            expires 1y;
            etag off;
            if_modified_since off;
			add_header Pragma "public";
            add_header Cache-Control "public, no-transform";

        # cache static portal content for one day 
        location ~* ^/(libs|doc|css|js)/.+\.(html|svg|js|css|jpg|jpeg|png|gif|ico|swf|woff|woff2)$ {
            expires 1d;
            etag off;
            if_modified_since off;
			add_header Pragma "public";
            add_header Cache-Control "public, no-transform";

		location / {
			index  index.html index.php;
			try_files $uri $uri/ /index.php$is_args$args;

		location ~ \.php$ {
			if ($request_uri ~* "^(.*/)index\.php$") {
				return 301 $1;
			try_files $uri =404;
			include        fastcgi_params;
			fastcgi_index  index.php;
			fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
		#error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        location ~ /\.ht {
            deny  all;



The below is a sample php.ini from a working NGINX installation with fastcgi PHP support.

It is contains only non-default settings with their comment-context and is intended as inspiration/starting point for your configuration - as-is and by no means as a final, complete configuration.

Necessary resource limits depend heavily on the amount of data passing through the application(s) deployed.

For Certificate Authority configuration (and download) please refer to https://www.php.net/manual/en/curl.configuration.php The absolute path to the downloaded cacert.pem need to be configured in curl.cainfo and openssl.cafile.

For further details refer to https://www.php.net/manual/en/install.php and the full sample/template php.ini files provded with your PHP installation.

; Resource Limits ;

; Maximum execution time of each script, in seconds
; https://php.net/max-execution-time
; Note: This directive is hardcoded to 0 for the CLI SAPI
max_execution_time = 300

; Maximum amount of time each script may spend parsing request data. It's a good
; idea to limit this time on productions servers in order to eliminate unexpectedly
; long running scripts.
; Note: This directive is hardcoded to -1 for the CLI SAPI
; Default Value: -1 (Unlimited)
; Development Value: 60 (60 seconds)
; Production Value: 60 (60 seconds)
; https://php.net/max-input-time
max_input_time = 300

; Maximum amount of memory a script may consume
; https://php.net/memory-limit
memory_limit = 512M

; Maximum size of POST data that PHP will accept.
; Its value may be 0 to disable the limit. It is ignored if POST data reading
; is disabled through enable_post_data_reading.
; https://php.net/post-max-size
post_max_size = 256M

; File Uploads ;

; Whether to allow HTTP file uploads.
; https://php.net/file-uploads
file_uploads = On

; Maximum allowed size for uploaded files.
; https://php.net/upload-max-filesize
upload_max_filesize = 128M

; Dynamic Extensions ;

; If you wish to have an extension loaded automatically, use the following
; syntax:
;   extension=modulename
; For example:
;   extension=mysqli
; When the extension library to load is not located in the default extension
; directory, You may specify an absolute path to the library file:
;   extension=/path/to/extension/mysqli.so
; Note : The syntax used in previous PHP versions ('extension=<ext>.so' and
; 'extension='php_<ext>.dll') is supported for legacy reasons and may be
; deprecated in a future PHP major version. So, when it is possible, please
; move to the new ('extension=<ext>) syntax.
; Notes for Windows environments :
; - Many DLL files are located in the extensions/ (PHP 4) or ext/ (PHP 5+)
;   extension folders as well as the separate PECL DLL download (PHP 5+).
;   Be sure to appropriately set the extension_dir directive.
extension=exif      ; Must be after mbstring as it depends on it
;extension=oci8_12c  ; Use with Oracle Database 12c Instant Client

; The MIBS data available in the PHP distribution must be installed.
; See http://www.php.net/manual/en/snmp.installation.php


; Module Settings ;

; Defines the default timezone used by the date functions
; https://php.net/date.timezone
date.timezone = Europe/Amsterdam

; A default value for the CURLOPT_CAINFO option. This is required to be an
; absolute path.
curl.cainfo = "path to ca.pem file"

; The location of a Certificate Authority (CA) file on the local filesystem
; to use when verifying the identity of SSL/TLS peers. Most users should
; not specify a value for this directive as PHP will attempt to use the
; OS-managed cert stores in its absence. If specified, this value may still
; be overridden on a per-stream basis via the "cafile" SSL stream context
; option.
openssl.cafile="path to ca.pem file"

Apache .htaccess

The below is a sample <INSTALL_ROOT>/public/.htaccess file from a working Apache (with PHP) installation.

This file is also included in the Portal Server package in this location.

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.php$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]


The graph below shows an overview of the supported version combinations of the Simian Suite components.

The arrows in the graph indicate required dependencies, e.g.: when running portal v0.3.1, front-end v0.6.3 needs to be installed for it to function. Similarly, if one of the application back-ends uses v1.5.0, front-end v0.7.0 is required. Any other front-end versions may be installed as desired.