diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..577e9b34acf306c10541bcdec308d311c20c663a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,63 @@
+-include scripts/make/base.Makefile
+-include scripts/make/docker.Makefile
+
+help::
+	@echo "$(APP_NAME) targets:"
+	@echo "    init.app        - init application environment"
+	@echo "    init.dev        - init development environment"
+	@echo "    lint            - verify code style"
+	@echo "    spell           - check spelling of text"
+	@echo "    format          - apply automatic formatting"
+	@echo "    build           - build a production bundle"
+	@echo "    run             - start app in development mode"
+	@echo "    run.prod        - start app in production mode"
+	@echo "    release         - tag and push release with current version"
+	$(call docker_help)
+
+# Settings
+
+DOCKER_TARGET ?= "prod"
+DOCKER_RUN = @docker run \
+		--name $(APP_NAME) \
+		--network="host" \
+		--env-file .env.docker \
+		-u $(UID):$(GID) \
+		$(DOCKER_ENTRY_POINT) \
+		autoradio/$(APP_NAME)
+
+
+# Targets
+
+init.app:: package.json
+	npm install
+	cp sample.env.production .env.production
+
+init.dev::
+	npm install
+	npm install -g cspell@latest
+	cp sample.env.development .env.development
+	cp sample.env.docker .env.docker
+
+lint::
+	npm run lint-eslint
+
+spell::
+	npm run spell
+
+format::
+	npm run format
+
+build::
+	npm run build
+
+run::
+	npm run dev
+
+run.prod::
+	npm run serve -- --host 0.0.0.0
+
+release:: VERSION := $(shell npm pkg get version | sed 's/"//g')
+release::
+	git tag $(VERSION)
+	git push origin $(VERSION)
+	@echo "Release '$(VERSION)' tagged and pushed successfully."
\ No newline at end of file
diff --git a/run.sh b/run.sh
deleted file mode 100755
index 94c8f9d0025dcf6c8ed982e120a3821dff5fc381..0000000000000000000000000000000000000000
--- a/run.sh
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/bin/bash
-mode="dev"
-docker="false"
-
-#
-# Run Script for AURA Player
-#
-# Call with one of these parameters:
-#
-# - dev
-# - build
-#
-
-if [[ $* =~ ^(dev|build)$ ]]; then
-	mode=$1
-fi
-
-if [[ "$1" == *"docker:"* ]]; then
-	docker="true"
-	mode=${1#*:}
-fi
-
-
-echo "[ Run mode=$mode ]"
-echo "[ Docker=$docker ]"
-
-
-
-# +++ DEFAULT COMMANDS +++ #
-
-if [[ $docker == "false" ]]; then
-
-	### Runs the local development server ###
-
-	if [[ $mode == "dev" ]]; then
-		(npm run dev)
-	fi
-
-	### Builds the bundle ###
-
-	if [[ $mode == "build" ]]; then
-		(npm run build)
-	fi
-
-fi
-
-
-# +++ DOCKER COMMANDS +++ #
-
-if [[ $docker == "true" ]]; then
-	BASE_DIR=$(readlink -f .)
-	AUDIO_DIR=$(readlink -f ./audio)
-	echo "Absolute base dir: " $BASE_DIR
-
-
-	if [[ $mode == "build" ]]; then
-		exec sudo docker build -t autoradio/dashboard .
-	fi
-
-	### Pushes the latest Docker Image to Docker Hub ###
-
-	if [[ $mode == "push" ]]; then
-		exec sudo docker push autoradio/dashboard
-	fi
-fi
diff --git a/scripts/make/base.Makefile b/scripts/make/base.Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..c966323d33cdcb04e7630bfa05616d02a27d8f80
--- /dev/null
+++ b/scripts/make/base.Makefile
@@ -0,0 +1,6 @@
+# Base config for AURA Makefiles
+# Include this at the top of other Makesfiles
+
+.DEFAULT_GOAL := help
+
+APP_NAME := $(shell basename $(dir $(abspath $(dir $$PWD/Makefile))))
diff --git a/scripts/make/docker.Makefile b/scripts/make/docker.Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..fe32497134bdaf7a90186ca8a39fbb24dfe34031
--- /dev/null
+++ b/scripts/make/docker.Makefile
@@ -0,0 +1,58 @@
+# Docker targets for AURA Makefiles
+
+
+# Help
+
+define docker_help
+	@echo "    docker.build    - build docker image"
+	@echo "    docker.push     - push docker image"
+	@echo "    docker.run      - start app in container"
+	@echo "    docker.run.i    - start app in container (interactive mode)"
+	@echo "    docker.run.bash - start bash in container"
+	@echo "    docker.restart  - restart container"
+	@echo "    docker.stop     - stop container"
+	@echo "    docker.rm       - stop and remove container"
+	@echo "    docker.log      - container logs for app"
+	@echo "    docker.bash     - enter bash in running container"
+endef
+
+# Dependencies
+
+docker.deps:
+	@which docker
+
+# Targets
+
+docker.build:: docker.deps
+	@docker build -t autoradio/$(APP_NAME) .
+
+docker.push:: docker.deps
+	@docker push autoradio/$(APP_NAME)
+
+# TODO Fix and extend to use correct entry points for dev/prod
+docker.run:: DOCKER_ENTRY_POINT := -d
+docker.run:: docker.deps
+	$(DOCKER_RUN)
+
+docker.run.i:: DOCKER_ENTRY_POINT := -it --rm
+docker.run.i:: docker.deps
+	$(DOCKER_RUN)
+
+docker.run.bash:: DOCKER_ENTRY_POINT := -v "$(CURDIR)":"/srv" --entrypoint bash -it --rm
+docker.run.bash:: docker.deps
+	$(DOCKER_RUN)
+
+docker.restart:: docker.deps
+	@docker restart $(APP_NAME)
+
+docker.stop:: docker.deps
+	@docker stop $(APP_NAME)
+
+docker.rm:: docker.stop
+	@docker rm $(APP_NAME)
+
+docker.log:: docker.deps
+	@docker logs $(APP_NAME) -f
+
+docker.bash:: docker.deps
+	@docker exec -it $(APP_NAME) bash