Welcome to Flindt’s documentation!

Installation

Prerequisites

If you want to run the front end without Docker you also need to have Gulp, NPM and Node.JS installed locally.

Docker environment

  1. Checkout the project on your computer with Git
git git@github.com:wearespindle/flindt.git
cd flindt
  1. Build the docker image. This takes a while the first time.
docker-compose build

Note

This command needs to run every time the Dockerfile, requirements or patches are adjusted. Good practice would be to run it every time the git repo is updated. If nothing changed, the command would complete almost instantly.

  1. First start the database-container and keep it running in the background. This container is needed by the backend-container.
docker-compose up -d db
  1. Do a migration of the models
docker-compose run --rm backend python manage.py migrate
  1. Create a superuser for your backend
docker-compose run --rm backend python manage.py createsuperuser
  1. Run the containers
docker-compose up

Visit the backend at http://localhost:8005/admin and login with the superuser you created. The front end is available at http://localhost:3000 (both via Docker as well as locally)

Google Login Setup

The Flindt tool uses Google Login to register and login users from the domain you whitelist. To set this up you need to go through a couple of steps:

  • Login to the Google APIs website
  • From the Overview screen, fill in Google+ API in the Search bar and select it from the search results
  • Click on the Enable button
  • Now you need to create Credentials. Click on the Credentials button in the navigation on the left.
  • Click on the blue Create Credentials button and select OAuth Client ID: * Application type? Web application
  • Give the credentials a name, e.g. Flindt
  • In Authorized JavaScript origins fill in your development url, e.g. localhost:3000
  • Click on the Save button
  • The current screen should be the Credentials overview; click on Flindt

The credentials are needed for our Google Login setup. For this to work we need to add them to a .env file

vim /flindt/backend/.env

Add the following information in your file:

SOCIAL_AUTH_GOOGLE_PLUS_KEY=your_client_id
SOCIAL_AUTH_GOOGLE_PLUS_SECRET=your_client_secret
SOCIAL_AUTH_GOOGLE_PLUS_WHITELISTED_DOMAINS=your_whitelisted_domains
CORS_ORIGIN_WHITELIST=localhost:3000,yourdomain.com

Django Social Auth

For the backend to work correctly with Google we need to add our ‘Application’ to the backend.

  • Go to http://localhost:8005/admin/oauth2_provider/application/ and log in with your superuser
  • Click on the Add application button in the topright
  • Replace the generated Client id with: DsHaTowmFoOr3GQLOOoJaXQpViaV6NsIFzOVY3ME
  • In the Client Type field, select: public
  • In the Authorization grand type select: Resource owner password-based
  • Press save

Go to localhost:3000 and click on the Login with Google button, you can now succesfully log in using your Google account.

Flindt without Docker

Introduction

This is a testcase aka. Proof of Concept to run the Spindle feedback-tool “Flindt” without permanent Docker-containers. The setup was done on macOS Sierra using Vagrant 1.9.7. for VirtualBox, using Vagrant Box debian/contrib-jessie64.

Vagrant plugins used:

  • vagrant-cachier
  • vagrant-hostsupdater
  • vagrant-share
  • vagrant-vbguest

Adding the Vagrantbox can be done with: vagrant box add debian/contrib-jessie64; installing a specific Vagrant-plugin with vagrant plugin install vagrant-cachier.

It is advised to use the Vagrantfile from the appendix below.

Note

Use your own DNS-names for cust.flindt.org (frontend) and api.cust.flindt.org (backend)!

Warning

You will also need user-accounts at GlassFrog, Google Developer and Slack to make full use of this holacracy feedback-tool!

Frontend

Start by building the static content use by the frontend.

Edit file frontend/src/constants/constants.js to contain the right value for your GOOGLE_CLIENT_ID.

Option 1

The easy way, still using Docker though…

Build with ./build-frontend.sh (see in appendix) outside of the Vagrant VM. For this, you need to have Docker installed on your host. The resulting folder uploads/ can be uploaded to a webserver. It contains static content (img / js / css).

FYI Vagrant will mount the whole Flindt-directory, including the generated content in upload, under /srv/flindt.

Option 2

Note

Installing NodeJS in the VM as described below, is not needed when you build the frontend one time with Docker and serve the generated static files from the upload-folder.

Install NodeJS in the VM

curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
apt-get install -y nodejs

Install node modules

npm install
export NODE_PATH=/srv/flindt/frontend/node_modules
npm install -g gulp-cli webpack@1.14.0

Vagrant / Linux

Run vagrant up.

Once the box is up and running, do vagrant ssh followed by sudo -i. You are now root in the virtual machine. Next install some essential packages. So as user root:

apt-get install python3.4-dev python3-pip virtualenvwrapper python3-virtualenv \
 libjpeg-dev curl zlib1g-dev mysql-server libmysqlclient-dev nginx-full

While installing, you will be prompted to set a password for the MySQL admin-user. Take note of this for later usage. You’ll need it to create a database in the next step and in the .env-file for the backend.

Add export WORKON_HOME="/srv/virtualenvs" to file /root/.bashrc. It’s needed for the backend’s virtualenv.

Setup the “virtualenvs”, based on Python 3.4:

mkdir -p /srv/virtualenvs
export WORKON_HOME="/srv/virtualenvs"
mkvirtualenv -a /srv/flindt -p /usr/bin/python3.4 flindt

Log out and back in as user root to activate the just installed virtualenv-functions.

(More on Python Virtual Environments.)

Backend

First create a MySQL-database name “flindt”:

# mysql -u root -p
Enter password:

mysql> create database flindt CHARACTER SET utf8 COLLATE utf8_general_ci;
Query OK, 1 row affected (0.00 sec)

mysql> exit

Run workon flindt to activate the virtualenv. The working directory will change to /srv/flindt.

Enter the backend-directory, upgrade pip and install the Python-packages as stated in the requirements-files:

cd backend
pip install -U pip
pip install -r requirements-dev.txt

In the file .env (in directory backend), adapt values as needed, e.g. the DATABASE_URL, MySQL-password and the server-names:

SOCIAL_AUTH_GOOGLE_PLUS_KEY=SomeSecretKey.apps.googleusercontent.com
CORS_ORIGIN_WHITELIST=localhost:8005,cust.flindt.org,api.cust.flindt.org
ALLOWED_HOSTS=localhost,127.0.0.1,cust.flindt.org,api.cust.flindt.org
DATABASE_URL=mysql://root:password@localhost/flindt
FRONTEND_HOSTNAME=cust.flindt.org
DEBUG=1

Now the application can be setup:

python manage.py migrate
python manage.py createsuperuser
python manage.py collectstatic

nginx

Web server “nginx” will be used to server the static content from the frontend in upload and as a reverse proxy to the uWSGI-server, listening on port 8005. Used config files can be found below in the appendix.

cd /etc/nginx/sites-available
cp *.flindt.org . # Copy the nginx vhosts-files from the appendix
cd ../sites-enabled
ln -s /etc/nginx/sites-available/* .
rm default
nginx -t # configuration test

uWSGI

Start uWSGI with uwsgi --daemonize2 uwsgi.log --ini flindt_backend.ini.

Again the used config file flindt_backend.ini can be found in the appendix.

Finally you can login with the superuser-account at http://api.cust.flindt.org/admin/ and add the application as described in flindt.readthedocs.io.

Connecting to the Flindt-frontend should result in a page that says Welcome to Flindt!

Google API

Some Google related errors encountered along the way, accompanied by what fixed it.

Not a valid origin

"Not a valid origin for the client: http://cust.flindt.org has not been whitelisted for \
client ID 197265621337-blahblahblah.apps.googleusercontent.com. Please go to \
https://console.developers.google.com/ and whitelist this origin for your project's client ID."

FIX: Domain verification from Google to DNS-provider.

Added domain “flindt.org” to the whitelist.

Not allowed access

XMLHttpRequest cannot load https://api.flindt.wearespindle.com/api-social-auth/convert-token/. \
Response to preflight request doesn't pass access control check: \
No 'Access-Control-Allow-Origin' header is present on the requested resource. \
Origin 'http://cust.flindt.org' is therefore not allowed access.

FIX: Recompile (and upload) the frontend with the right name / URL in file constants.js!

Can’t reach Google API / error 502

XMLHttpRequest cannot load http://api.cust.flindt.org/api-social-auth/convert-token/. \
Response to preflight request doesn't pass access control check: \
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin \
'http://cust.flindt.org' is therefore not allowed access. The response had HTTP status code 502.

FIX: Added wide-open CORS-config to nginx vhost-config cust.flindt.org.

See CORS on Nginx.

Appendix

Configuration files

Configuration files not found in the default Flindt repository.

Vagrant

Note

Entry cust.flindt.org is added by Vagrant, but you’ll need to add a line 192.168.33.10 api.cust.flindt.org to file /etc/hosts manually!

File Vagrantfile:

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.provider :virtualbox do |vb|

    # change the network card hardware for better performance
    vb.customize ["modifyvm", :id, "--nictype1", "virtio" ]
    vb.customize ["modifyvm", :id, "--nictype2", "virtio" ]

    # suggested fix for slow network performance
    # see https://github.com/mitchellh/vagrant/issues/1807
    vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
    vb.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
  end

  config.vm.box = "debian/contrib-jessie64"
  config.ssh.insert_key = false

  config.vbguest.auto_update = false

  # To speed up installation cache packages
  # on the local drive
  if Vagrant.has_plugin?("vagrant-cachier")
    config.cache.scope = :box
    config.cache.synced_folder_opts = {
      type: :nfs,
      mount_options: ['rw', 'vers=3', 'tcp', 'nolock']
    }
  end

  config.vm.synced_folder "./", "/srv/flindt", type: "nfs"

  config.vm.network "private_network", ip: "192.168.33.10"
  config.vm.hostname = 'cust.flindt.org'
  # Add 'api.cust.flindt.org' to /etc/hosts manually !!
  config.vm.network "forwarded_port", guest: 443, host: 443
  config.vm.network "forwarded_port", guest: 80, host: 80

  config.vm.provider "virtualbox" do |vb|
    vb.memory = "2048"
  end

end
nginx vhosts

The frontend-server.

File cust.flindt.org:

server {

  listen 80 default;
  server_name cust.flindt.org;

  root /srv/flindt/upload;

# Wide-open CORS config for nginx
# https://enable-cors.org/server_nginx.html
location / {
     if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        #
        # Custom headers and headers various browsers *should* be OK with but aren't
        #
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
        #
        # Tell client that this pre-flight info is valid for 20 days
        #
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain charset=UTF-8';
        add_header 'Content-Length' 0;
        return 204;
     }
     if ($request_method = 'POST') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
        add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
     }
     if ($request_method = 'GET') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
        add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
     }
}

}

The backend-server, which serves the API.

File api.cust.flindt.org:

server {

  listen 80;
  server_name api.cust.flindt.org;

  location /static/ {
    alias /srv/flindt/backend/flindt/static/;
  }

  location / {
    #if ($http_x_forwarded_proto != "https") {
    #  rewrite ^(.*)$ https://$http_host$1 permanent;
    #}

    proxy_pass http://127.0.0.1:8005;
  }

}
uWSGI

File flindt_backend.ini:

[uwsgi]
virtualenv = /srv/virtualenvs/flindt
chdir = /srv/flindt/backend
wsgi-file = /srv/flindt/backend/flindt/wsgi.py

module = flindt.wsgi:application
env DJANGO_SETTINGS_MODULE = flindt.settings
master = true
pidfile = /tmp/project-master.pid
http = 0.0.0.0:8005
processes = 5
harakiri = 1000
max-requests = 5000
TODO
  • HTTPS / certificates for CUSTOMER.flindt.org and api.CUSTOMER.flindt.org, preferably with Let’s Encrypt and Caddyserver.

Data

GlassFrog

To be able to give and receive feedback you need to run a GlassFrog import.

  • Go to http://localhost:8005/admin/organization/organization/ and log in with your superuser
  • Click on the Add organization button in the top right
  • Add the name of your organization
  • To import data from GlassFrog you’ll need an API key, go to https://app.glassfrog.com/api_keys to obtain one
  • Fill in your newly obtained API key in the Glassfrog api key field
  • Fill in the GlassFrog anchor circle id, this is the top level circle, click on the main circle in GlassFrog and copy the id from the URL
  • Press save
  • Click on your newly generated Organization
  • First click on the Import users from this organization button
  • After the first import is completed, you can use the Import roles for this organization button to import all the roles, if you want to

exclude roles from being imported you can use the ‘flindt-exclude’ tag in GlassFrog. Go to a role in GlassFrog and click on ‘add tag’, to add ‘flindt-exclude’.

You now have all the data necessary for starting a feedback round

Starting to work

Rounds

The following steps explain how to start a round

  • Go to http://localhost:8005/admin/round/round/add/ and log in with your superuser
  • Choose the amount of people that have to give and receive feedback (called senders and receivers)
  • Set the start and end date (people can’t give or edit feedback after a round ends)
  • Set a description for the specific round
  • Select how many roles you want people to give feedback on
  • Select how many people you want to give personal feedback to
  • Select the amount of minimal feedback to give a user has
  • Select a question or add a new one
    • This question will be asked if someone gives feedback to a colleague on a personal level.
  • Click on save, go to your newly created round and click the Start the round button on the top right to start the round

Personal feedback

We thought of a way that breaks the boring tedious ways of giving feedback to someone on a personal level. A way to do this is to use metaphors, which will help people to think on a different scale about someone, and will help them think of positives and improvements more easily and more creatively.

Think of questions like: * If this person was a car, what kind of car would he be? * If you could think of an animal that would describe this person, which animal would that be?

Role feedback

Role feedback exists of so called ‘Ratings’. These ratings are the types of feedback asked about when giving someone feedback on a role.

An example of ratings can be:

  • Improvements
  • Positives

These ratings get added automatically to a role feedback form. So if you add 25 ratings, the user will be prompted to answer 25 ratings when giving feedback on a role. We suggest to keep them as simple and descriptive as possible.

You can add ratings by clicking on Feedback in the navigation of the admin and clicking on Ratings.

Indices and tables