This repository contains the source code of the ‘Dein Geschenk’ App used at the Baden State Museum: https://www.landesmuseum.de/deingeschenk.
Gift is made by the artist group, Blast Theory as part of a three year research project funded by the European Union’s Horizon 2020 research and innovation programme under grant agreement No 727040. It is a collaboration with IT University Copenhagen, University of Nottingham, University of Uppsala, Blast Theory, Next Game, the Europeana Foundation and Culture24.
Further details can be found here:
The application was adapted and developed further for the Baden State Museum by the project team Creative Collections consisting of Johannes Bernhardt, Tilmann Bruhn and Christiane Lindner, as well as the extended Creative-family Leilah Jätzold, Danica Schlosser and Tim Weiland. For further information refer to www.landesmuseum.de/creative.
This app is comprised of:
- A frontend mobile web-app built with React in TypeScript
- A backend API built with Koa.js in TypeScript utilizing a PostgreSQL DB
For further details, see:
- Linux
- NodeJS 12+ / Yarn (to build / run the project)
- PostgreSQL (recommended) or SQLite3 database (to store user-generated gift data)
- AWS S3 bucket (to store user-generated media assets)
- FFmpeg 3.4+ (to convert user-generated media assets to a common format)
The bucket should be set to allow some public access (by ACL). To set these go to:
S3 > your-bucket > permissions > Block public access
The following restrictions should NOT be turned on:
- [OFF] Block all public access
- [OFF] Block public access to buckets and objects granted through new access control lists (ACLs)
- [OFF] Block public access to buckets and objects granted through any access control lists (ACLs)
See the following screenshot for appropriate settings:
In order for the app to upload and retrieve media from the bucket, it must have an appropriate CORS config.
To set this go to:
S3 > your-bucket > permissions > CORS configuration
And add the following:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
</CORSRule>
</CORSConfiguration>
The API needs to be provided with valid AWS credentials to allow it use the
S3 bucket. These are passed to the api in the environment / config variables
AWS_ACCESS_KEY
and AWS_SECRET_ACCESS_KEY
The credentials you provide will need to be attached to a user / role with the following policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObjectAcl",
"s3:GetObject",
"s3:AbortMultipartUpload",
"s3:PutObjectVersionAcl",
"s3:GetObjectTagging",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::my-gift-bucket/*"
}
]
}
Note, my-gift-bucket
should be the name of the bucket you created at the
beginning. If you would like to limit the access further by environment, you
can restrict the resource field to e.g.
"Resource": "arn:aws:s3:::my-gift-bucket/production/*"
instead.
If you’d rather avoid AWS S3 completely. You could try something like MinIO which provides a compatibility with S3 (though this is entirely untested). Or you could create an alternative StorageService which, for example uses the local filesystem instead.
First, enter psql:
sudo su - postgres
psql
Now, there are three things we need to do.
Create the database and make sure it shows up in the list of all databases.
create database gift;
\l
Create the user, make sure the user shows up in the list of all users, then set the user’s password.
create user gift;
\du
\password gift;
Transfer ownership to our new user and grant them all privileges
grant all privileges on database gift to gift;
alter database gift owner to gift;
If you want to run both the app and the API on the same server, you’re going to need to use Nginx. Here’s an example config:
user www-data; worker_processes auto; pid /run/nginx.pid; include /etc/nginx/modules-enabled/*.conf; events { worker_connections 768; # multi_accept on; } http { ## # Basic Settings ## sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; # server_tokens off; # server_names_hash_bucket_size 64; # server_name_in_redirect off; include /etc/nginx/mime.types; default_type application/octet-stream; ## # SSL Settings ## ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; ## # Logging Settings ## access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; ## # Gzip Settings ## gzip on; # gzip_vary on; # gzip_proxied any; # gzip_comp_level 6; # gzip_buffers 16 8k; # gzip_http_version 1.1; # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; ## # Virtual Host Configs ## include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; server { listen 80; listen [::]:80; server_name testgeschenk.de; # TODO : Change me! return 301 https://$server_name$request_uri; } server { listen 443 ssl; listen [::]:443 ssl; server_name testgeschenk.de; # TODO: Change me! ssl_certificate /etc/nginx/ssl/nginx.cer; # TODO: Make sure you add your own cert file here! ssl_certificate_key /etc/nginx/ssl/nginx.key; # TODO: Make sure you add your own key file here! ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers HIGH:!aNULL:!MD5; location / { proxy_pass https://127.0.0.1:8000; } location /api { proxy_pass http://127.0.0.1:5000; # TODO: Make sure you're using the API port here. } } }
Do the TODO’s in the config, then save the file at /etc/nginx/nginx.conf
and run nginx.
- Install all the Requirements
- Double-check that you’re using NodeJS version 12
- Follow the steps in AWS S3 Bucket Setup
- Follow the steps in PostgreSQL Database Setup
- Install dependencies
cd api yarn install cd ../app yarn install
- Configure the API environment variables
cd api cp example.env .env vim .env
- Change the four AWS variables at the bottom to match the values for your bucket
- Change the SQL URI to match that of your user + database combination (format
postgresql://user:password@ip:port/dbname
)- Using the port
5432
should work by default
- Using the port
- Changing
ENVIRONMENT
is probably recommended, but leaving it asdevelopment
works fine. - Set
USE_API_PREFIX
totrue
. This will add/api
as a prefix to all API routes.
- Follow the steps in Nginx Setup
- Configure the app environment variables
cd app vim .env.development
Change the api url to
https://yourdomain/api
- Run the API and the app
- I recommend using the process manager pm2
- Install with
npm install pm2 -g
- Install with
- Start the API
cd api pm2 start yarn --name "api" -- start
- Start the app
cd app pm2 start yarn --name "app" -- start-app
- Some handy pm2 commands:
pm2 list
,pm2 logs
,pm2 monit
- I recommend using the process manager pm2
- You’re done!
- Check that everything is running on your domain
- If something isn’t working, let us know. Perhaps we missed a step in this manual.
API:
cd api
# Install dependencies
yarn install
# Setup default configuration
cp example.env .env
# Update config with custom values
vi .env
# Run the api (with verbose logging)
export DEBUG='(DEBUG|INFO|WARN|ERROR):*'
yarn start
APP:
cd app
# Install dependencies
yarn install
# Run the app
yarn start-app
You should now be able to open http://localhost:8000 in your web browser to interact with your locally running gift app.
Currently the code to run the app contains information specific to a demo museum, the Brighton Museum, and the Munch Museum. The following files / directories should be considered for customisation:
High-level configuration for the museums. This is where the particular museum data used to run the current instance of the app is determined (by inspecting the domain the app is being served from).
May be used to provide pre-made gift data in the app before falling back to an api lookup.
Global css theming.
Provides switching of background image.
Contains the audio assets used in the gift creation / receiving process.
Contains the text transcription for the audio files.
Contains the text for the popup modal asking users to accept terms and conditions.
Contains copy for the terms-and-conditions / privacy.
Contains copy for the help / FAQs.