diff --git a/plane/README.md b/plane/README.md
new file mode 100644
index 0000000..f7db4a8
--- /dev/null
+++ b/plane/README.md
@@ -0,0 +1,4 @@
+# Supabase
+
+- copied from https://github.com/makeplane/plane
+- removed `ports`
diff --git a/plane/code/.env.example b/plane/code/.env.example
new file mode 100644
index 0000000..4120ee5
--- /dev/null
+++ b/plane/code/.env.example
@@ -0,0 +1,51 @@
+APP_DOMAIN=localhost
+APP_RELEASE=stable
+
+WEB_REPLICAS=1
+SPACE_REPLICAS=1
+ADMIN_REPLICAS=1
+API_REPLICAS=1
+
+NGINX_PORT=80
+WEB_URL=http://${APP_DOMAIN}
+DEBUG=0
+SENTRY_DSN=
+SENTRY_ENVIRONMENT=production
+CORS_ALLOWED_ORIGINS=http://${APP_DOMAIN}
+
+#DB SETTINGS
+PGHOST=plane-db
+PGDATABASE=plane
+POSTGRES_USER=plane
+POSTGRES_PASSWORD=plane
+POSTGRES_DB=plane
+POSTGRES_PORT=5432
+PGDATA=/var/lib/postgresql/data
+DATABASE_URL=
+
+# REDIS SETTINGS
+REDIS_HOST=plane-redis
+REDIS_PORT=6379
+REDIS_URL=
+
+# Secret Key
+SECRET_KEY=60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5
+
+# DATA STORE SETTINGS
+USE_MINIO=1
+AWS_REGION=
+AWS_ACCESS_KEY_ID=access-key
+AWS_SECRET_ACCESS_KEY=secret-key
+AWS_S3_ENDPOINT_URL=http://plane-minio:9000
+AWS_S3_BUCKET_NAME=uploads
+MINIO_ROOT_USER=access-key
+MINIO_ROOT_PASSWORD=secret-key
+BUCKET_NAME=uploads
+FILE_SIZE_LIMIT=5242880
+
+# Gunicorn Workers
+GUNICORN_WORKERS=1
+
+# UNCOMMENT `DOCKER_PLATFORM` IF YOU ARE ON `ARM64` AND DOCKER IMAGE IS NOT AVAILABLE FOR RESPECTIVE `APP_RELEASE`
+# DOCKER_PLATFORM=linux/amd64
+
diff --git a/plane/code/README.md b/plane/code/README.md
new file mode 100644
index 0000000..d93d85c
--- /dev/null
+++ b/plane/code/README.md
@@ -0,0 +1,483 @@
+# Self Hosting
+
+In this guide, we will walk you through the process of setting up a self-hosted environment. Self-hosting allows you to have full control over your applications and data. It's a great way to ensure privacy, control, and customization.
+
+We will cover two main options for setting up your self-hosted environment: using a cloud server or using your desktop. For the cloud server, we will use an AWS EC2 instance. For the desktop, we will use Docker to create a local environment.
+
+Let's get started!
+
+## Setting up Docker Environment
+
+
+ Option 1 - Using Cloud Server
+
Best way to start is to create EC2 machine on AWS. It must have minimum of 2vCPU and 4GB RAM.
+
Run the below command to install docker engine.
+
+`curl -fsSL https://get.docker.com | sh -`
+
+
+
+---
+
+
+ Option 2 - Using Desktop
+
+#### For Mac
+
+
+
Download Docker Desktop for Mac from the Docker Hub.
+
Double-click the downloaded `.dmg` file and drag the Docker app icon to the Applications folder.
+
Open Docker Desktop from the Applications folder. You might be asked to provide your system password to install additional software.
+
+
+#### For Windows:
+
+
+
Download Docker Desktop for Windows from the Docker Hub.
+
Run the installer and follow the instructions. You might be asked to enable Hyper-V and "Containers" Windows features.
+
Open Docker Desktop. You might be asked to log out and log back in, or restart your machine, for changes to take effect.
+
+
+After installation, you can verify the installation by opening a terminal (Command Prompt on Windows, Terminal app on Mac) and running the command `docker --version`. This should display the installed version of Docker.
+
+
+
+---
+
+## Installing Plane
+
+Installing plane is a very easy and minimal step process.
+
+### Prerequisite
+
+- Docker installed and running
+- OS with bash scripting enabled (Ubuntu, Linux AMI, macos). Windows systems need to have [gitbash](https://git-scm.com/download/win)
+- User context used must have access to docker services. In most cases, use sudo su to switch as root user
+- Use the terminal (or gitbash) window to run all the future steps
+
+### Downloading Latest Stable Release
+
+```
+mkdir plane-selfhost
+
+cd plane-selfhost
+
+curl -fsSL -o setup.sh https://raw.githubusercontent.com/makeplane/plane/master/deploy/selfhost/install.sh
+
+chmod +x setup.sh
+```
+
+---
+
+### Proceed with setup
+
+Above steps will set you ready to install and start plane services.
+
+Lets get started by running the `./setup.sh` command.
+
+This will prompt you with the below options.
+
+```bash
+Select a Action you want to perform:
+ 1) Install (x86_64)
+ 2) Start
+ 3) Stop
+ 4) Restart
+ 5) Upgrade
+ 6) View Logs
+ 7) Backup Data
+ 8) Exit
+Action [2]: 1
+```
+
+For the 1st time setup, type "1" as action input.
+
+This will create a create a folder `plane-app` or `plane-app-preview` (in case of preview deployment) and will download 2 files inside that
+
+- `docker-compose.yaml`
+- `plane.env`
+
+Again the `options [1-8]` will be popped up and this time hit `8` to exit.
+
+---
+
+### Continue with setup - Environment Settings
+
+Before proceeding, we suggest used to review `.env` file and set the values.
+Below are the most import keys you must refer to. _You can use any text editor to edit this file_.
+
+> `NGINX_PORT` - This is default set to `80`. Make sure the port you choose to use is not preoccupied. (e.g `NGINX_PORT=8080`)
+
+> `WEB_URL` - This is default set to `http://localhost`. Change this to the FQDN you plan to use along with NGINX_PORT (eg. `https://plane.example.com:8080` or `http://[IP-ADDRESS]:8080`)
+
+> `CORS_ALLOWED_ORIGINS` - This is default set to `http://localhost`. Change this to the FQDN you plan to use along with NGINX_PORT (eg. `https://plane.example.com:8080` or `http://[IP-ADDRESS]:8080`)
+
+There are many other settings you can play with, but we suggest you configure `EMAIL SETTINGS` as it will enable you to invite your teammates onto the platform.
+
+---
+
+### Continue with setup - Start Server
+
+Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `2` to start the sevices
+
+```bash
+Select a Action you want to perform:
+ 1) Install (x86_64)
+ 2) Start
+ 3) Stop
+ 4) Restart
+ 5) Upgrade
+ 6) View Logs
+ 7) Backup Data
+ 8) Exit
+
+Action [2]: 2
+```
+
+Expect something like this.
+
+
+Be patient as it might take sometime based on download speed and system configuration. If all goes well, you must see something like this
+
+
+
+This is the confirmation that all images were downloaded and the services are up & running.
+
+You have successfully self hosted `Plane` instance. Access the application by going to IP or domain you have configured it (e.g `https://plane.example.com:8080` or `http://[IP-ADDRESS]:8080`)
+
+---
+
+### Stopping the Server
+
+In case you want to make changes to `.env` variables, we suggest you to stop the services before doing that.
+
+Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `3` to stop the sevices
+
+```bash
+Select a Action you want to perform:
+ 1) Install (x86_64)
+ 2) Start
+ 3) Stop
+ 4) Restart
+ 5) Upgrade
+ 6) View Logs
+ 7) Backup Data
+ 8) Exit
+
+Action [2]: 3
+```
+
+If all goes well, you must see something like this
+
+
+
+---
+
+### Restarting the Server
+
+In case you want to make changes to `.env` variables, without stopping the server or you noticed some abnormalies in services, you can restart the services with RESTART option.
+
+Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `4` to restart the sevices
+
+```bash
+Select a Action you want to perform:
+ 1) Install (x86_64)
+ 2) Start
+ 3) Stop
+ 4) Restart
+ 5) Upgrade
+ 6) View Logs
+ 7) Backup Data
+ 8) Exit
+
+Action [2]: 4
+```
+
+If all goes well, you must see something like this
+
+
+
+---
+
+### Upgrading Plane Version
+
+It is always advised to keep Plane up to date with the latest release.
+
+Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `5` to upgrade the release.
+
+```bash
+Select a Action you want to perform:
+ 1) Install (x86_64)
+ 2) Start
+ 3) Stop
+ 4) Restart
+ 5) Upgrade
+ 6) View Logs
+ 7) Backup Data
+ 8) Exit
+
+Action [2]: 5
+```
+
+By choosing this, it will stop the services and then will download the latest `docker-compose.yaml` and `plane.env`.
+
+You must expect the below message
+
+
+
+Once done, choose `8` to exit from prompt.
+
+> It is very important for you to validate the `plane.env` for the new changes.
+
+Once done with making changes in `plane.env` file, jump on to `Start Server`
+
+---
+
+### View Logs
+
+There would a time when you might want to check what is happening inside the API, Worker or any other container.
+
+Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `6` to view logs.
+
+```bash
+Select a Action you want to perform:
+ 1) Install (x86_64)
+ 2) Start
+ 3) Stop
+ 4) Restart
+ 5) Upgrade
+ 6) View Logs
+ 7) Backup Data
+ 8) Exit
+
+Action [2]: 6
+```
+
+
+This will further open sub-menu with list of services
+```bash
+Select a Service you want to view the logs for:
+ 1) Web
+ 2) Space
+ 3) API
+ 4) Worker
+ 5) Beat-Worker
+ 6) Migrator
+ 7) Proxy
+ 8) Redis
+ 9) Postgres
+ 10) Minio
+ 0) Back to Main Menu
+
+Service:
+```
+
+Select any of the service to view the logs e.g. `3`. Expect something similar to this
+```bash
+api-1 | Waiting for database...
+api-1 | Database available!
+api-1 | Waiting for database migrations to complete...
+api-1 | Waiting for database migrations to complete...
+api-1 | Waiting for database migrations to complete...
+api-1 | Waiting for database migrations to complete...
+api-1 | Waiting for database migrations to complete...
+api-1 | Waiting for database migrations to complete...
+api-1 | Waiting for database migrations to complete...
+api-1 | No migrations Pending. Starting processes ...
+api-1 | Instance registered
+api-1 | ENABLE_SIGNUP loaded with value from environment variable.
+api-1 | ENABLE_EMAIL_PASSWORD loaded with value from environment variable.
+api-1 | ENABLE_MAGIC_LINK_LOGIN loaded with value from environment variable.
+api-1 | GOOGLE_CLIENT_ID loaded with value from environment variable.
+api-1 | GITHUB_CLIENT_ID loaded with value from environment variable.
+api-1 | GITHUB_CLIENT_SECRET loaded with value from environment variable.
+api-1 | EMAIL_HOST loaded with value from environment variable.
+api-1 | EMAIL_HOST_USER loaded with value from environment variable.
+api-1 | EMAIL_HOST_PASSWORD loaded with value from environment variable.
+api-1 | EMAIL_PORT loaded with value from environment variable.
+api-1 | EMAIL_FROM loaded with value from environment variable.
+api-1 | EMAIL_USE_TLS loaded with value from environment variable.
+api-1 | EMAIL_USE_SSL loaded with value from environment variable.
+api-1 | OPENAI_API_KEY loaded with value from environment variable.
+api-1 | GPT_ENGINE loaded with value from environment variable.
+api-1 | UNSPLASH_ACCESS_KEY loaded with value from environment variable.
+api-1 | Checking bucket...
+api-1 | Bucket 'uploads' does not exist. Creating bucket...
+api-1 | Bucket 'uploads' created successfully.
+api-1 | Public read access policy set for bucket 'uploads'.
+api-1 | Cache Cleared
+api-1 | [2024-05-02 03:56:01 +0000] [1] [INFO] Starting gunicorn 21.2.0
+api-1 | [2024-05-02 03:56:01 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1)
+api-1 | [2024-05-02 03:56:01 +0000] [1] [INFO] Using worker: uvicorn.workers.UvicornWorker
+api-1 | [2024-05-02 03:56:01 +0000] [25] [INFO] Booting worker with pid: 25
+api-1 | [2024-05-02 03:56:03 +0000] [25] [INFO] Started server process [25]
+api-1 | [2024-05-02 03:56:03 +0000] [25] [INFO] Waiting for application startup.
+api-1 | [2024-05-02 03:56:03 +0000] [25] [INFO] ASGI 'lifespan' protocol appears unsupported.
+api-1 | [2024-05-02 03:56:03 +0000] [25] [INFO] Application startup complete.
+
+```
+
+To exit this, use `CTRL+C` and then you will land on to the main-menu with the list of actions.
+
+Similarly, you can view the logs of other services.
+
+---
+
+### Backup Data
+
+There would a time when you might want to backup your data from docker volumes to external storage like S3 or drives.
+
+Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `7` to Backup the data.
+
+```bash
+Select a Action you want to perform:
+ 1) Install (x86_64)
+ 2) Start
+ 3) Stop
+ 4) Restart
+ 5) Upgrade
+ 6) View Logs
+ 7) Backup Data
+ 8) Exit
+
+Action [2]: 7
+```
+
+In response, you can find the backup folder
+
+```bash
+Backing Up plane-app_pgdata
+Backing Up plane-app_redisdata
+Backing Up plane-app_uploads
+
+Backup completed successfully. Backup files are stored in /....../plane-app/backup/20240502-1120
+```
+
+---
+
+### Restore Data
+
+When you want to restore the previously backed-up data, follow the instructions below.
+
+1. Make sure that Plane-CE is installed, started, and then stopped. This ensures that the Docker volumes are created.
+
+1. Download the restore script using the command below. We suggest downloading it in the same folder as `setup.sh`.
+
+ ```bash
+ curl -fsSL -o restore.sh https://raw.githubusercontent.com/makeplane/plane/master/deploy/selfhost/restore.sh
+ chmod +x restore.sh
+ ```
+
+1. Execute the command below to restore your data.
+
+ ```bash
+ ./restore.sh
+ ```
+
+ As an example, for a backup folder `/opt/plane-selfhost/plane-app/backup/20240722-0914`, expect the response below:
+
+ ```bash
+ --------------------------------------------
+ ____ _ /////////
+ | _ \| | __ _ _ __ ___ /////////
+ | |_) | |/ _` | '_ \ / _ \ ///// /////
+ | __/| | (_| | | | | __/ ///// /////
+ |_| |_|\__,_|_| |_|\___| ////
+ ////
+ --------------------------------------------
+ Project management tool from the future
+ --------------------------------------------
+ Found /opt/plane-selfhost/plane-app/backup/20240722-0914/pgdata.tar.gz
+ .....Restoring plane-app_pgdata
+ .....Successfully restored volume plane-app_pgdata from pgdata.tar.gz
+
+ Found /opt/plane-selfhost/plane-app/backup/20240722-0914/redisdata.tar.gz
+ .....Restoring plane-app_redisdata
+ .....Successfully restored volume plane-app_redisdata from redisdata.tar.gz
+
+ Found /opt/plane-selfhost/plane-app/backup/20240722-0914/uploads.tar.gz
+ .....Restoring plane-app_uploads
+ .....Successfully restored volume plane-app_uploads from uploads.tar.gz
+
+
+ Restore completed successfully.
+ ```
+
+1. Start the Plane instance using `./setup.sh start`.
+
+---
+
+
+
Upgrading from v0.13.2 to v0.14.x
+
+This is one time activity for users who are upgrading from v0.13.2 to v0.14.0
+
+As there has been significant changes to Self Hosting process, this step mainly covers the data migration from current (v0.13.2) docker volumes from newly created volumes
+
+> Before we begin with migration, make sure your v0.14.0 was started and then stopped. This is required to know the newly created docker volume names.
+
+Begin with downloading the migration script using below command
+
+```
+
+curl -fsSL -o migrate.sh https://raw.githubusercontent.com/makeplane/plane/master/deploy/selfhost/migration-0.13-0.14.sh
+
+chmod +x migrate.sh
+
+```
+
+Now run the `./migrate.sh` command and expect the instructions as below
+
+```
+******************************************************************
+
+This script is solely for the migration purpose only.
+This is a 1 time migration of volume data from v0.13.2 => v0.14.x
+
+Assumption:
+1. Postgres data volume name ends with _pgdata
+2. Minio data volume name ends with _uploads
+3. Redis data volume name ends with _redisdata
+
+Any changes to this script can break the migration.
+
+Before you proceed, make sure you run the below command
+to know the docker volumes
+
+docker volume ls -q | grep -i "_pgdata"
+docker volume ls -q | grep -i "_uploads"
+docker volume ls -q | grep -i "_redisdata"
+
+*******************************************************
+
+Given below list of REDIS volumes, identify the prefix of source and destination volumes leaving "_redisdata"
+---------------------
+plane-app_redisdata
+v0132_redisdata
+
+Provide the Source Volume Prefix :
+```
+
+**Open another terminal window**, and run the mentioned 3 command. This may be different for users who have changed the volume names in their previous setup (v0.13.2)
+
+For every command you must see 2 records something like shown in above example of `redisdata`
+
+To move forward, you would need PREFIX of old setup and new setup. As per above example, `v0132` is the prefix of v0.13.2 and `plane-app` is the prefix of v0.14.0 setup
+
+**Back to original terminal window**, _Provide the Source Volume Prefix_ and hit ENTER.
+
+Now you will be prompted to _Provide Destination Volume Prefix_. Provide the value and hit ENTER
+
+```
+Provide the Source Volume Prefix : v0132
+Provide the Destination Volume Prefix : plane-app
+```
+
+In case the suffixes are wrong or the mentioned volumes are not found, you will receive the error shown below. The image below displays an error for source volumes.
+
+
+
+In case of successful migration, it will be a silent exit without error.
+
+Now its time to restart v0.14.0 setup.
+
\ No newline at end of file
diff --git a/plane/code/build.yml b/plane/code/build.yml
new file mode 100644
index 0000000..b65d297
--- /dev/null
+++ b/plane/code/build.yml
@@ -0,0 +1,30 @@
+services:
+ web:
+ image: ${DOCKERHUB_USER:-local}/plane-frontend:${APP_RELEASE:-latest}
+ build:
+ context: .
+ dockerfile: ./web/Dockerfile.web
+
+ space:
+ image: ${DOCKERHUB_USER:-local}/plane-space:${APP_RELEASE:-latest}
+ build:
+ context: ./
+ dockerfile: ./space/Dockerfile.space
+
+ admin:
+ image: ${DOCKERHUB_USER:-local}/plane-admin:${APP_RELEASE:-latest}
+ build:
+ context: ./
+ dockerfile: ./admin/Dockerfile.admin
+
+ api:
+ image: ${DOCKERHUB_USER:-local}/plane-backend:${APP_RELEASE:-latest}
+ build:
+ context: ./apiserver
+ dockerfile: ./Dockerfile.api
+
+ proxy:
+ image: ${DOCKERHUB_USER:-local}/plane-proxy:${APP_RELEASE:-latest}
+ build:
+ context: ./nginx
+ dockerfile: ./Dockerfile
diff --git a/plane/code/docker-compose.yml b/plane/code/docker-compose.yml
new file mode 100644
index 0000000..dacc35f
--- /dev/null
+++ b/plane/code/docker-compose.yml
@@ -0,0 +1,184 @@
+x-app-env: &app-env
+ environment:
+ - NGINX_PORT=${NGINX_PORT:-80}
+ - WEB_URL=${WEB_URL:-http://localhost}
+ - DEBUG=${DEBUG:-0}
+ - SENTRY_DSN=${SENTRY_DSN}
+ - SENTRY_ENVIRONMENT=${SENTRY_ENVIRONMENT:-"production"}
+ - CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS}
+ # Gunicorn Workers
+ - GUNICORN_WORKERS=${GUNICORN_WORKERS:-1}
+ #DB SETTINGS
+ - PGHOST=${PGHOST:-plane-db}
+ - PGDATABASE=${PGDATABASE:-plane}
+ - POSTGRES_USER=${POSTGRES_USER:-plane}
+ - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-plane}
+ - POSTGRES_DB=${POSTGRES_DB:-plane}
+ - POSTGRES_PORT=${POSTGRES_PORT:-5432}
+ - PGDATA=${PGDATA:-/var/lib/postgresql/data}
+ - DATABASE_URL=${DATABASE_URL:-postgresql://plane:plane@plane-db/plane}
+ # REDIS SETTINGS
+ - REDIS_HOST=${REDIS_HOST:-plane-redis}
+ - REDIS_PORT=${REDIS_PORT:-6379}
+ - REDIS_URL=${REDIS_URL:-redis://plane-redis:6379/}
+ # Application secret
+ - SECRET_KEY=${SECRET_KEY:-60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5}
+ # DATA STORE SETTINGS
+ - USE_MINIO=${USE_MINIO:-1}
+ - AWS_REGION=${AWS_REGION:-""}
+ - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-"access-key"}
+ - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-"secret-key"}
+ - AWS_S3_ENDPOINT_URL=${AWS_S3_ENDPOINT_URL:-http://plane-minio:9000}
+ - AWS_S3_BUCKET_NAME=${AWS_S3_BUCKET_NAME:-uploads}
+ - MINIO_ROOT_USER=${MINIO_ROOT_USER:-"access-key"}
+ - MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD:-"secret-key"}
+ - BUCKET_NAME=${BUCKET_NAME:-uploads}
+ - FILE_SIZE_LIMIT=${FILE_SIZE_LIMIT:-5242880}
+ # Admin and Space URLs
+ - ADMIN_BASE_URL=${ADMIN_BASE_URL}
+ - SPACE_BASE_URL=${SPACE_BASE_URL}
+ - APP_BASE_URL=${APP_BASE_URL}
+
+services:
+ web:
+ <<: *app-env
+ image: ${DOCKERHUB_USER:-makeplane}/plane-frontend:${APP_RELEASE:-stable}
+ platform: ${DOCKER_PLATFORM:-}
+ pull_policy: if_not_present
+ restart: unless-stopped
+ command: node web/server.js web
+ deploy:
+ replicas: ${WEB_REPLICAS:-1}
+ depends_on:
+ - api
+ - worker
+
+ space:
+ <<: *app-env
+ image: ${DOCKERHUB_USER:-makeplane}/plane-space:${APP_RELEASE:-stable}
+ platform: ${DOCKER_PLATFORM:-}
+ pull_policy: if_not_present
+ restart: unless-stopped
+ command: node space/server.js space
+ deploy:
+ replicas: ${SPACE_REPLICAS:-1}
+ depends_on:
+ - api
+ - worker
+ - web
+
+ admin:
+ <<: *app-env
+ image: ${DOCKERHUB_USER:-makeplane}/plane-admin:${APP_RELEASE:-stable}
+ platform: ${DOCKER_PLATFORM:-}
+ pull_policy: if_not_present
+ restart: unless-stopped
+ command: node admin/server.js admin
+ deploy:
+ replicas: ${ADMIN_REPLICAS:-1}
+ depends_on:
+ - api
+ - web
+
+ api:
+ <<: *app-env
+ image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
+ platform: ${DOCKER_PLATFORM:-}
+ pull_policy: if_not_present
+ restart: unless-stopped
+ command: ./bin/docker-entrypoint-api.sh
+ deploy:
+ replicas: ${API_REPLICAS:-1}
+ volumes:
+ - logs_api:/code/plane/logs
+ depends_on:
+ - plane-db
+ - plane-redis
+
+ worker:
+ <<: *app-env
+ image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
+ platform: ${DOCKER_PLATFORM:-}
+ pull_policy: if_not_present
+ restart: unless-stopped
+ command: ./bin/docker-entrypoint-worker.sh
+ volumes:
+ - logs_worker:/code/plane/logs
+ depends_on:
+ - api
+ - plane-db
+ - plane-redis
+
+ beat-worker:
+ <<: *app-env
+ image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
+ platform: ${DOCKER_PLATFORM:-}
+ pull_policy: if_not_present
+ restart: unless-stopped
+ command: ./bin/docker-entrypoint-beat.sh
+ volumes:
+ - logs_beat-worker:/code/plane/logs
+ depends_on:
+ - api
+ - plane-db
+ - plane-redis
+
+ migrator:
+ <<: *app-env
+ image: ${DOCKERHUB_USER:-makeplane}/plane-backend:${APP_RELEASE:-stable}
+ platform: ${DOCKER_PLATFORM:-}
+ pull_policy: if_not_present
+ restart: "no"
+ command: ./bin/docker-entrypoint-migrator.sh
+ volumes:
+ - logs_migrator:/code/plane/logs
+ depends_on:
+ - plane-db
+ - plane-redis
+
+ plane-db:
+ <<: *app-env
+ image: postgres:15.5-alpine
+ pull_policy: if_not_present
+ restart: unless-stopped
+ command: postgres -c 'max_connections=1000'
+ volumes:
+ - pgdata:/var/lib/postgresql/data
+
+ plane-redis:
+ <<: *app-env
+ image: valkey/valkey:7.2.5-alpine
+ pull_policy: if_not_present
+ restart: unless-stopped
+ volumes:
+ - redisdata:/data
+
+ plane-minio:
+ <<: *app-env
+ image: minio/minio:latest
+ pull_policy: if_not_present
+ restart: unless-stopped
+ command: server /export --console-address ":9090"
+ volumes:
+ - uploads:/export
+
+ # Comment this if you already have a reverse proxy running
+ proxy:
+ <<: *app-env
+ image: ${DOCKERHUB_USER:-makeplane}/plane-proxy:${APP_RELEASE:-stable}
+ platform: ${DOCKER_PLATFORM:-}
+ pull_policy: if_not_present
+ restart: unless-stopped
+ depends_on:
+ - web
+ - api
+ - space
+
+volumes:
+ pgdata:
+ redisdata:
+ uploads:
+ logs_api:
+ logs_worker:
+ logs_beat-worker:
+ logs_migrator:
diff --git a/plane/code/images/download.png b/plane/code/images/download.png
new file mode 100644
index 0000000..bb0d118
Binary files /dev/null and b/plane/code/images/download.png differ
diff --git a/plane/code/images/migrate-error.png b/plane/code/images/migrate-error.png
new file mode 100644
index 0000000..f42ec44
Binary files /dev/null and b/plane/code/images/migrate-error.png differ
diff --git a/plane/code/images/restart.png b/plane/code/images/restart.png
new file mode 100644
index 0000000..0387599
Binary files /dev/null and b/plane/code/images/restart.png differ
diff --git a/plane/code/images/started.png b/plane/code/images/started.png
new file mode 100644
index 0000000..d6a0a0b
Binary files /dev/null and b/plane/code/images/started.png differ
diff --git a/plane/code/images/stopped.png b/plane/code/images/stopped.png
new file mode 100644
index 0000000..0f58768
Binary files /dev/null and b/plane/code/images/stopped.png differ
diff --git a/plane/code/images/upgrade.png b/plane/code/images/upgrade.png
new file mode 100644
index 0000000..b78fbbb
Binary files /dev/null and b/plane/code/images/upgrade.png differ
diff --git a/plane/code/install.sh b/plane/code/install.sh
new file mode 100755
index 0000000..8fd2e3e
--- /dev/null
+++ b/plane/code/install.sh
@@ -0,0 +1,559 @@
+#!/bin/bash
+
+BRANCH=${BRANCH:-master}
+SCRIPT_DIR=$PWD
+SERVICE_FOLDER=plane-app
+PLANE_INSTALL_DIR=$PWD/$SERVICE_FOLDER
+export APP_RELEASE="stable"
+export DOCKERHUB_USER=makeplane
+export PULL_POLICY=${PULL_POLICY:-if_not_present}
+
+CPU_ARCH=$(uname -m)
+
+mkdir -p $PLANE_INSTALL_DIR/archive
+DOCKER_FILE_PATH=$PLANE_INSTALL_DIR/docker-compose.yaml
+DOCKER_ENV_PATH=$PLANE_INSTALL_DIR/plane.env
+
+function print_header() {
+clear
+
+cat <<"EOF"
+--------------------------------------------
+ ____ _ /////////
+| _ \| | __ _ _ __ ___ /////////
+| |_) | |/ _` | '_ \ / _ \ ///// /////
+| __/| | (_| | | | | __/ ///// /////
+|_| |_|\__,_|_| |_|\___| ////
+ ////
+--------------------------------------------
+Project management tool from the future
+--------------------------------------------
+EOF
+}
+
+function spinner() {
+ local pid=$1
+ local delay=.5
+ local spinstr='|/-\'
+
+ if ! ps -p "$pid" > /dev/null; then
+ echo "Invalid PID: $pid"
+ return 1
+ fi
+ while ps -p "$pid" > /dev/null; do
+ local temp=${spinstr#?}
+ printf " [%c] " "$spinstr" >&2
+ local spinstr=$temp${spinstr%"$temp"}
+ sleep $delay
+ printf "\b\b\b\b\b\b" >&2
+ done
+ printf " \b\b\b\b" >&2
+}
+
+function initialize(){
+ printf "Please wait while we check the availability of Docker images for the selected release ($APP_RELEASE) with ${CPU_ARCH^^} support." >&2
+
+ if [ "$CUSTOM_BUILD" == "true" ]; then
+ echo "" >&2
+ echo "" >&2
+ echo "${CPU_ARCH^^} images are not available for selected release ($APP_RELEASE)." >&2
+ echo "build"
+ return 1
+ fi
+
+ local IMAGE_NAME=makeplane/plane-proxy
+ local IMAGE_TAG=${APP_RELEASE}
+ docker manifest inspect "${IMAGE_NAME}:${IMAGE_TAG}" | grep -q "\"architecture\": \"${CPU_ARCH}\"" &
+ local pid=$!
+ spinner "$pid"
+
+ echo "" >&2
+
+ wait "$pid"
+
+ if [ $? -eq 0 ]; then
+ echo "Plane supports ${CPU_ARCH}" >&2
+ echo "available"
+ return 0
+ else
+ echo "" >&2
+ echo "" >&2
+ echo "${CPU_ARCH^^} images are not available for selected release ($APP_RELEASE)." >&2
+ echo "" >&2
+ echo "build"
+ return 1
+ fi
+}
+function getEnvValue() {
+ local key=$1
+ local file=$2
+
+ if [ -z "$key" ] || [ -z "$file" ]; then
+ echo "Invalid arguments supplied"
+ exit 1
+ fi
+
+ if [ -f "$file" ]; then
+ grep -q "^$key=" "$file"
+ if [ $? -eq 0 ]; then
+ local value
+ value=$(grep "^$key=" "$file" | cut -d'=' -f2)
+ echo "$value"
+ else
+ echo ""
+ fi
+ fi
+}
+function updateEnvFile() {
+ local key=$1
+ local value=$2
+ local file=$3
+
+ if [ -z "$key" ] || [ -z "$value" ] || [ -z "$file" ]; then
+ echo "Invalid arguments supplied"
+ exit 1
+ fi
+
+ if [ -f "$file" ]; then
+ # check if key exists in the file
+ grep -q "^$key=" "$file"
+ if [ $? -ne 0 ]; then
+ echo "$key=$value" >> "$file"
+ return
+ else
+ # if key exists, update the value
+ sed -i "s/^$key=.*/$key=$value/g" "$file"
+ fi
+ else
+ echo "File not found: $file"
+ exit 1
+ fi
+}
+
+function updateCustomVariables(){
+ echo "Updating custom variables..." >&2
+ updateEnvFile "DOCKERHUB_USER" "$DOCKERHUB_USER" "$DOCKER_ENV_PATH"
+ updateEnvFile "APP_RELEASE" "$APP_RELEASE" "$DOCKER_ENV_PATH"
+ updateEnvFile "PULL_POLICY" "$PULL_POLICY" "$DOCKER_ENV_PATH"
+ updateEnvFile "CUSTOM_BUILD" "$CUSTOM_BUILD" "$DOCKER_ENV_PATH"
+ echo "Custom variables updated successfully" >&2
+}
+
+function syncEnvFile(){
+ echo "Syncing environment variables..." >&2
+ if [ -f "$PLANE_INSTALL_DIR/plane.env.bak" ]; then
+ updateCustomVariables
+
+ # READ keys of plane.env and update the values from plane.env.bak
+ while IFS= read -r line
+ do
+ # ignore is the line is empty or starts with #
+ if [ -z "$line" ] || [[ $line == \#* ]]; then
+ continue
+ fi
+ key=$(echo "$line" | cut -d'=' -f1)
+ value=$(getEnvValue "$key" "$PLANE_INSTALL_DIR/plane.env.bak")
+ if [ -n "$value" ]; then
+ updateEnvFile "$key" "$value" "$DOCKER_ENV_PATH"
+ fi
+ done < "$DOCKER_ENV_PATH"
+ fi
+ echo "Environment variables synced successfully" >&2
+}
+
+function buildYourOwnImage(){
+ echo "Building images locally..."
+
+ export DOCKERHUB_USER="myplane"
+ export APP_RELEASE="local"
+ export PULL_POLICY="never"
+ CUSTOM_BUILD="true"
+
+ # checkout the code to ~/tmp/plane folder and build the images
+ local PLANE_TEMP_CODE_DIR=~/tmp/plane
+ rm -rf $PLANE_TEMP_CODE_DIR
+ mkdir -p $PLANE_TEMP_CODE_DIR
+ REPO=https://github.com/makeplane/plane.git
+ git clone "$REPO" "$PLANE_TEMP_CODE_DIR" --branch "$BRANCH" --single-branch --depth 1
+
+ cp "$PLANE_TEMP_CODE_DIR/deploy/selfhost/build.yml" "$PLANE_TEMP_CODE_DIR/build.yml"
+
+ cd "$PLANE_TEMP_CODE_DIR" || exit
+
+ /bin/bash -c "$COMPOSE_CMD -f build.yml build --no-cache" >&2
+ if [ $? -ne 0 ]; then
+ echo "Build failed. Exiting..."
+ exit 1
+ fi
+ echo "Build completed successfully"
+ echo ""
+ echo "You can now start the services by running the command: ./setup.sh start"
+ echo ""
+}
+
+function install() {
+ echo "Begin Installing Plane"
+ echo ""
+
+ local build_image=$(initialize)
+
+ if [ "$build_image" == "build" ]; then
+ # ask for confirmation to continue building the images
+ echo "Do you want to continue with building the Docker images locally?"
+ read -p "Continue? [y/N]: " confirm
+ if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
+ echo "Exiting..."
+ exit 0
+ fi
+ fi
+
+ if [ "$build_image" == "build" ]; then
+ download "true"
+ else
+ download "false"
+ fi
+}
+
+function download() {
+ local LOCAL_BUILD=$1
+ cd $SCRIPT_DIR
+ TS=$(date +%s)
+ if [ -f "$PLANE_INSTALL_DIR/docker-compose.yaml" ]
+ then
+ mv $PLANE_INSTALL_DIR/docker-compose.yaml $PLANE_INSTALL_DIR/archive/$TS.docker-compose.yaml
+ fi
+
+ curl -H 'Cache-Control: no-cache, no-store' -s -o $PLANE_INSTALL_DIR/docker-compose.yaml https://raw.githubusercontent.com/makeplane/plane/$BRANCH/deploy/selfhost/docker-compose.yml?$(date +%s)
+ curl -H 'Cache-Control: no-cache, no-store' -s -o $PLANE_INSTALL_DIR/variables-upgrade.env https://raw.githubusercontent.com/makeplane/plane/$BRANCH/deploy/selfhost/variables.env?$(date +%s)
+
+ if [ -f "$DOCKER_ENV_PATH" ];
+ then
+ cp "$DOCKER_ENV_PATH" "$PLANE_INSTALL_DIR/archive/$TS.env"
+ cp "$DOCKER_ENV_PATH" "$PLANE_INSTALL_DIR/plane.env.bak"
+ fi
+
+ mv $PLANE_INSTALL_DIR/variables-upgrade.env $DOCKER_ENV_PATH
+
+ syncEnvFile
+
+ if [ "$LOCAL_BUILD" == "true" ]; then
+ export DOCKERHUB_USER="myplane"
+ export APP_RELEASE="local"
+ export PULL_POLICY="never"
+ CUSTOM_BUILD="true"
+
+ buildYourOwnImage
+
+ if [ $? -ne 0 ]; then
+ echo ""
+ echo "Build failed. Exiting..."
+ exit 1
+ fi
+ updateCustomVariables
+ else
+ CUSTOM_BUILD="false"
+ updateCustomVariables
+ /bin/bash -c "$COMPOSE_CMD -f $DOCKER_FILE_PATH --env-file=$DOCKER_ENV_PATH pull --policy always"
+
+ if [ $? -ne 0 ]; then
+ echo ""
+ echo "Failed to pull the images. Exiting..."
+ exit 1
+ fi
+ fi
+
+ echo ""
+ echo "Most recent version of Plane is now available for you to use"
+ echo ""
+ echo "In case of 'Upgrade', please check the 'plane.env 'file for any new variables and update them accordingly"
+ echo ""
+}
+function startServices() {
+ /bin/bash -c "$COMPOSE_CMD -f $DOCKER_FILE_PATH --env-file=$DOCKER_ENV_PATH up -d --pull if_not_present --quiet-pull"
+
+ local migrator_container_id=$(docker container ls -aq -f "name=$SERVICE_FOLDER-migrator")
+ if [ -n "$migrator_container_id" ]; then
+ local idx=0
+ while docker inspect --format='{{.State.Status}}' $migrator_container_id | grep -q "running"; do
+ local message=">> Waiting for Data Migration to finish"
+ local dots=$(printf '%*s' $idx | tr ' ' '.')
+ echo -ne "\r$message$dots"
+ ((idx++))
+ sleep 1
+ done
+ fi
+ printf "\r\033[K"
+ echo ""
+ echo " Data Migration completed successfully ✅"
+
+ # if migrator exit status is not 0, show error message and exit
+ if [ -n "$migrator_container_id" ]; then
+ local migrator_exit_code=$(docker inspect --format='{{.State.ExitCode}}' $migrator_container_id)
+ if [ $migrator_exit_code -ne 0 ]; then
+ echo "Plane Server failed to start ❌"
+ # stopServices
+ echo
+ echo "Please check the logs for the 'migrator' service and resolve the issue(s)."
+ echo "Stop the services by running the command: ./setup.sh stop"
+ exit 1
+ fi
+ fi
+
+ local api_container_id=$(docker container ls -q -f "name=$SERVICE_FOLDER-api")
+ local idx2=0
+ while ! docker logs $api_container_id 2>&1 | grep -m 1 -i "Application startup complete" | grep -q ".";
+ do
+ local message=">> Waiting for API Service to Start"
+ local dots=$(printf '%*s' $idx2 | tr ' ' '.')
+ echo -ne "\r$message$dots"
+ ((idx2++))
+ sleep 1
+ done
+ printf "\r\033[K"
+ echo " API Service started successfully ✅"
+ source "${DOCKER_ENV_PATH}"
+ echo " Plane Server started successfully ✅"
+ echo ""
+ echo " You can access the application at $WEB_URL"
+ echo ""
+
+}
+function stopServices() {
+ /bin/bash -c "$COMPOSE_CMD -f $DOCKER_FILE_PATH --env-file=$DOCKER_ENV_PATH down"
+}
+function restartServices() {
+ stopServices
+ startServices
+}
+function upgrade() {
+ echo "***** STOPPING SERVICES ****"
+ stopServices
+
+ echo
+ echo "***** DOWNLOADING STABLE VERSION ****"
+ install
+
+ echo "***** PLEASE VALIDATE AND START SERVICES ****"
+}
+function viewSpecificLogs(){
+ local SERVICE_NAME=$1
+
+ if /bin/bash -c "$COMPOSE_CMD -f $DOCKER_FILE_PATH ps | grep -q '$SERVICE_NAME'"; then
+ echo "Service '$SERVICE_NAME' is running."
+ else
+ echo "Service '$SERVICE_NAME' is not running."
+ fi
+
+ /bin/bash -c "$COMPOSE_CMD -f $DOCKER_FILE_PATH logs -f $SERVICE_NAME"
+}
+function viewLogs(){
+
+ ARG_SERVICE_NAME=$2
+
+ if [ -z "$ARG_SERVICE_NAME" ];
+ then
+ echo
+ echo "Select a Service you want to view the logs for:"
+ echo " 1) Web"
+ echo " 2) Space"
+ echo " 3) API"
+ echo " 4) Worker"
+ echo " 5) Beat-Worker"
+ echo " 6) Migrator"
+ echo " 7) Proxy"
+ echo " 8) Redis"
+ echo " 9) Postgres"
+ echo " 10) Minio"
+ echo " 0) Back to Main Menu"
+ echo
+ read -p "Service: " DOCKER_SERVICE_NAME
+
+ until (( DOCKER_SERVICE_NAME >= 0 && DOCKER_SERVICE_NAME <= 10 )); do
+ echo "Invalid selection. Please enter a number between 1 and 11."
+ read -p "Service: " DOCKER_SERVICE_NAME
+ done
+
+ if [ -z "$DOCKER_SERVICE_NAME" ];
+ then
+ echo "INVALID SERVICE NAME SUPPLIED"
+ else
+ case $DOCKER_SERVICE_NAME in
+ 1) viewSpecificLogs "web";;
+ 2) viewSpecificLogs "space";;
+ 3) viewSpecificLogs "api";;
+ 4) viewSpecificLogs "worker";;
+ 5) viewSpecificLogs "beat-worker";;
+ 6) viewSpecificLogs "migrator";;
+ 7) viewSpecificLogs "proxy";;
+ 8) viewSpecificLogs "plane-redis";;
+ 9) viewSpecificLogs "plane-db";;
+ 10) viewSpecificLogs "plane-minio";;
+ 0) askForAction;;
+ *) echo "INVALID SERVICE NAME SUPPLIED";;
+ esac
+ fi
+ elif [ -n "$ARG_SERVICE_NAME" ];
+ then
+ ARG_SERVICE_NAME=$(echo "$ARG_SERVICE_NAME" | tr '[:upper:]' '[:lower:]')
+ case $ARG_SERVICE_NAME in
+ web) viewSpecificLogs "web";;
+ space) viewSpecificLogs "space";;
+ api) viewSpecificLogs "api";;
+ worker) viewSpecificLogs "worker";;
+ beat-worker) viewSpecificLogs "beat-worker";;
+ migrator) viewSpecificLogs "migrator";;
+ proxy) viewSpecificLogs "proxy";;
+ redis) viewSpecificLogs "plane-redis";;
+ postgres) viewSpecificLogs "plane-db";;
+ minio) viewSpecificLogs "plane-minio";;
+ *) echo "INVALID SERVICE NAME SUPPLIED";;
+ esac
+ else
+ echo "INVALID SERVICE NAME SUPPLIED"
+ fi
+}
+function backupSingleVolume() {
+ backupFolder=$1
+ selectedVolume=$2
+ # Backup data from Docker volume to the backup folder
+ # docker run --rm -v "$selectedVolume":/source -v "$backupFolder":/backup busybox sh -c 'cp -r /source/* /backup/'
+ local tobereplaced="plane-app_"
+ local replacewith=""
+
+ local svcName="${selectedVolume//$tobereplaced/$replacewith}"
+
+ docker run --rm \
+ -e TAR_NAME="$svcName" \
+ -v "$selectedVolume":/"$svcName" \
+ -v "$backupFolder":/backup \
+ busybox sh -c 'tar -czf "/backup/${TAR_NAME}.tar.gz" /${TAR_NAME}'
+}
+function backupData() {
+ local datetime=$(date +"%Y%m%d-%H%M")
+ local BACKUP_FOLDER=$PLANE_INSTALL_DIR/backup/$datetime
+ mkdir -p "$BACKUP_FOLDER"
+
+ volumes=$(docker volume ls -f "name=plane-app" --format "{{.Name}}" | grep -E "_pgdata|_redisdata|_uploads")
+ # Check if there are any matching volumes
+ if [ -z "$volumes" ]; then
+ echo "No volumes found starting with 'plane-app'"
+ exit 1
+ fi
+
+ for vol in $volumes; do
+ echo "Backing Up $vol"
+ backupSingleVolume "$BACKUP_FOLDER" "$vol"
+ done
+
+ echo ""
+ echo "Backup completed successfully. Backup files are stored in $BACKUP_FOLDER"
+ echo ""
+
+}
+function askForAction() {
+ local DEFAULT_ACTION=$1
+
+ if [ -z "$DEFAULT_ACTION" ];
+ then
+ echo
+ echo "Select a Action you want to perform:"
+ echo " 1) Install"
+ echo " 2) Start"
+ echo " 3) Stop"
+ echo " 4) Restart"
+ echo " 5) Upgrade"
+ echo " 6) View Logs"
+ echo " 7) Backup Data"
+ echo " 8) Exit"
+ echo
+ read -p "Action [2]: " ACTION
+ until [[ -z "$ACTION" || "$ACTION" =~ ^[1-8]$ ]]; do
+ echo "$ACTION: invalid selection."
+ read -p "Action [2]: " ACTION
+ done
+
+ if [ -z "$ACTION" ];
+ then
+ ACTION=2
+ fi
+ echo
+ fi
+
+ if [ "$ACTION" == "1" ] || [ "$DEFAULT_ACTION" == "install" ];
+ then
+ install
+ # askForAction
+ elif [ "$ACTION" == "2" ] || [ "$DEFAULT_ACTION" == "start" ];
+ then
+ startServices
+ # askForAction
+ elif [ "$ACTION" == "3" ] || [ "$DEFAULT_ACTION" == "stop" ];
+ then
+ stopServices
+ # askForAction
+ elif [ "$ACTION" == "4" ] || [ "$DEFAULT_ACTION" == "restart" ];
+ then
+ restartServices
+ # askForAction
+ elif [ "$ACTION" == "5" ] || [ "$DEFAULT_ACTION" == "upgrade" ];
+ then
+ upgrade
+ # askForAction
+ elif [ "$ACTION" == "6" ] || [ "$DEFAULT_ACTION" == "logs" ];
+ then
+ viewLogs "$@"
+ askForAction
+ elif [ "$ACTION" == "7" ] || [ "$DEFAULT_ACTION" == "backup" ];
+ then
+ backupData
+ elif [ "$ACTION" == "8" ]
+ then
+ exit 0
+ else
+ echo "INVALID ACTION SUPPLIED"
+ fi
+}
+
+# if docker-compose is installed
+if command -v docker-compose &> /dev/null
+then
+ COMPOSE_CMD="docker-compose"
+else
+ COMPOSE_CMD="docker compose"
+fi
+
+if [ "$CPU_ARCH" == "x86_64" ] || [ "$CPU_ARCH" == "amd64" ]; then
+ CPU_ARCH="amd64"
+elif [ "$CPU_ARCH" == "aarch64" ] || [ "$CPU_ARCH" == "arm64" ]; then
+ CPU_ARCH="arm64"
+fi
+
+if [ -f "$DOCKER_ENV_PATH" ]; then
+ DOCKERHUB_USER=$(getEnvValue "DOCKERHUB_USER" "$DOCKER_ENV_PATH")
+ APP_RELEASE=$(getEnvValue "APP_RELEASE" "$DOCKER_ENV_PATH")
+ PULL_POLICY=$(getEnvValue "PULL_POLICY" "$DOCKER_ENV_PATH")
+ CUSTOM_BUILD=$(getEnvValue "CUSTOM_BUILD" "$DOCKER_ENV_PATH")
+
+ if [ -z "$DOCKERHUB_USER" ]; then
+ DOCKERHUB_USER=makeplane
+ updateEnvFile "DOCKERHUB_USER" "$DOCKERHUB_USER" "$DOCKER_ENV_PATH"
+ fi
+
+ if [ -z "$APP_RELEASE" ]; then
+ APP_RELEASE=stable
+ updateEnvFile "APP_RELEASE" "$APP_RELEASE" "$DOCKER_ENV_PATH"
+ fi
+
+ if [ -z "$PULL_POLICY" ]; then
+ PULL_POLICY=if_not_present
+ updateEnvFile "PULL_POLICY" "$PULL_POLICY" "$DOCKER_ENV_PATH"
+ fi
+
+ if [ -z "$CUSTOM_BUILD" ]; then
+ CUSTOM_BUILD=false
+ updateEnvFile "CUSTOM_BUILD" "$CUSTOM_BUILD" "$DOCKER_ENV_PATH"
+ fi
+fi
+
+print_header
+askForAction "$@"
diff --git a/plane/code/migration-0.13-0.14.sh b/plane/code/migration-0.13-0.14.sh
new file mode 100755
index 0000000..d03f877
--- /dev/null
+++ b/plane/code/migration-0.13-0.14.sh
@@ -0,0 +1,118 @@
+#!/bin/bash
+
+echo '
+******************************************************************
+
+This script is solely for the migration purpose only.
+This is a 1 time migration of volume data from v0.13.2 => v0.14.x
+
+Assumption:
+1. Postgres data volume name ends with _pgdata
+2. Minio data volume name ends with _uploads
+3. Redis data volume name ends with _redisdata
+
+Any changes to this script can break the migration.
+
+Before you proceed, make sure you run the below command
+to know the docker volumes
+
+docker volume ls -q | grep -i "_pgdata"
+docker volume ls -q | grep -i "_uploads"
+docker volume ls -q | grep -i "_redisdata"
+
+*******************************************************
+'
+
+DOWNLOAD_FOL=./download
+rm -rf ${DOWNLOAD_FOL}
+mkdir -p ${DOWNLOAD_FOL}
+
+function volumeExists {
+ if [ "$(docker volume ls -f name=$1 | awk '{print $NF}' | grep -E '^'$1'$')" ]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+function readPrefixes(){
+ echo ''
+ echo 'Given below list of REDIS volumes, identify the prefix of source and destination volumes leaving "_redisdata" '
+ echo '---------------------'
+ docker volume ls -q | grep -i "_redisdata"
+ echo ''
+
+ read -p "Provide the Source Volume Prefix : " SRC_VOL_PREFIX
+ until [ "$SRC_VOL_PREFIX" ]; do
+ read -p "Provide the Source Volume Prefix : " SRC_VOL_PREFIX
+ done
+
+ read -p "Provide the Destination Volume Prefix : " DEST_VOL_PREFIX
+ until [ "$DEST_VOL_PREFIX" ]; do
+ read -p "Provide the Source Volume Prefix : " DEST_VOL_PREFIX
+ done
+
+ echo ''
+ echo 'Prefix Provided '
+ echo " Source : ${SRC_VOL_PREFIX}"
+ echo " Destination : ${DEST_VOL_PREFIX}"
+ echo '---------------------------------------'
+}
+
+function migrate(){
+
+ SRC_VOLUME=${SRC_VOL_PREFIX}_${VOL_NAME_SUFFIX}
+ DEST_VOLUME=${DEST_VOL_PREFIX}_${VOL_NAME_SUFFIX}
+
+ if volumeExists $SRC_VOLUME; then
+ if volumeExists $DEST_VOLUME; then
+ GOOD_TO_GO=1
+ else
+ echo "Destination Volume '$DEST_VOLUME' does not exist"
+ echo ''
+ fi
+ else
+ echo "Source Volume '$SRC_VOLUME' does not exist"
+ echo ''
+ fi
+
+ if [ $GOOD_TO_GO = 1 ]; then
+
+ echo "MIGRATING ${VOL_NAME_SUFFIX} FROM ${SRC_VOLUME} => ${DEST_VOLUME}"
+
+ TEMP_CONTAINER=$(docker run -d -v $SRC_VOLUME:$CONTAINER_VOL_FOLDER busybox true)
+ docker cp -q $TEMP_CONTAINER:$CONTAINER_VOL_FOLDER ${DOWNLOAD_FOL}/${VOL_NAME_SUFFIX}
+ docker rm $TEMP_CONTAINER &> /dev/null
+
+ TEMP_CONTAINER=$(docker run -d -v $DEST_VOLUME:$CONTAINER_VOL_FOLDER busybox true)
+ if [ "$VOL_NAME_SUFFIX" = "pgdata" ]; then
+ docker cp -q ${DOWNLOAD_FOL}/${VOL_NAME_SUFFIX} $TEMP_CONTAINER:$CONTAINER_VOL_FOLDER/_temp
+ docker run --rm -v $DEST_VOLUME:$CONTAINER_VOL_FOLDER \
+ -e DATA_FOLDER="${CONTAINER_VOL_FOLDER}" \
+ busybox /bin/sh -c 'cp -Rf $DATA_FOLDER/_temp/* $DATA_FOLDER '
+ else
+ docker cp -q ${DOWNLOAD_FOL}/${VOL_NAME_SUFFIX} $TEMP_CONTAINER:$CONTAINER_VOL_FOLDER
+ fi
+ docker rm $TEMP_CONTAINER &> /dev/null
+
+ echo ''
+ fi
+}
+
+readPrefixes
+
+# MIGRATE DB
+CONTAINER_VOL_FOLDER=/var/lib/postgresql/data
+VOL_NAME_SUFFIX=pgdata
+migrate
+
+# MIGRATE REDIS
+CONTAINER_VOL_FOLDER=/data
+VOL_NAME_SUFFIX=redisdata
+migrate
+
+# MIGRATE MINIO
+CONTAINER_VOL_FOLDER=/export
+VOL_NAME_SUFFIX=uploads
+migrate
+
diff --git a/plane/code/restore.sh b/plane/code/restore.sh
new file mode 100755
index 0000000..cd453b2
--- /dev/null
+++ b/plane/code/restore.sh
@@ -0,0 +1,121 @@
+#!/bin/bash
+
+function print_header() {
+clear
+
+cat <<"EOF"
+--------------------------------------------
+ ____ _ /////////
+| _ \| | __ _ _ __ ___ /////////
+| |_) | |/ _` | '_ \ / _ \ ///// /////
+| __/| | (_| | | | | __/ ///// /////
+|_| |_|\__,_|_| |_|\___| ////
+ ////
+--------------------------------------------
+Project management tool from the future
+--------------------------------------------
+EOF
+}
+
+function restoreSingleVolume() {
+ selectedVolume=$1
+ backupFolder=$2
+ restoreFile=$3
+
+ docker volume rm "$selectedVolume" > /dev/null 2>&1
+
+ if [ $? -ne 0 ]; then
+ echo "Error: Failed to remove volume $selectedVolume"
+ echo ""
+ return 1
+ fi
+
+ docker volume create "$selectedVolume" > /dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ echo "Error: Failed to create volume $selectedVolume"
+ echo ""
+ return 1
+ fi
+
+ docker run --rm \
+ -e TAR_NAME="$restoreFile" \
+ -v "$selectedVolume":"/vol" \
+ -v "$backupFolder":/backup \
+ busybox sh -c 'mkdir -p /restore && tar -xzf "/backup/${TAR_NAME}.tar.gz" -C /restore && mv /restore/${TAR_NAME}/* /vol'
+
+ if [ $? -ne 0 ]; then
+ echo "Error: Failed to restore volume ${selectedVolume} from ${restoreFile}.tar.gz"
+ echo ""
+ return 1
+ fi
+ echo ".....Successfully restored volume $selectedVolume from ${restoreFile}.tar.gz"
+ echo ""
+}
+
+function restoreData() {
+ print_header
+ local BACKUP_FOLDER=${1:-$PWD}
+
+ local dockerServiceStatus
+ dockerServiceStatus=$($COMPOSE_CMD ls --filter name=plane-app --format=json | jq -r .[0].Status)
+ local dockerServicePrefix
+ dockerServicePrefix="running"
+
+ if [[ $dockerServiceStatus == $dockerServicePrefix* ]]; then
+ echo "Plane App is running. Please STOP the Plane App before restoring data."
+ exit 1
+ fi
+
+ local volumes
+ volumes=$(docker volume ls -f "name=plane-app" --format "{{.Name}}" | grep -E "_pgdata|_redisdata|_uploads")
+ # Check if there are any matching volumes
+ if [ -z "$volumes" ]; then
+ echo ".....No volumes found starting with 'plane-app'"
+ exit 1
+ fi
+
+
+ for BACKUP_FILE in $BACKUP_FOLDER/*.tar.gz; do
+ if [ -e "$BACKUP_FILE" ]; then
+
+ local restoreFileName
+ restoreFileName=$(basename "$BACKUP_FILE")
+ restoreFileName="${restoreFileName%.tar.gz}"
+
+ local restoreVolName
+ restoreVolName="plane-app_${restoreFileName}"
+ echo "Found $BACKUP_FILE"
+
+ local docVol
+ docVol=$(docker volume ls -f "name=$restoreVolName" --format "{{.Name}}" | grep -E "_pgdata|_redisdata|_uploads")
+
+ if [ -z "$docVol" ]; then
+ echo "Skipping: No volume found with name $restoreVolName"
+ else
+ echo ".....Restoring $docVol"
+ restoreSingleVolume "$docVol" "$BACKUP_FOLDER" "$restoreFileName"
+ fi
+ else
+ echo "No .tar.gz files found in the current directory."
+ echo ""
+ echo "Please provide the path to the backup file."
+ echo ""
+ echo "Usage: ./restore.sh /path/to/backup"
+ exit 1
+ fi
+ done
+
+ echo ""
+ echo "Restore completed successfully."
+ echo ""
+}
+
+# if docker-compose is installed
+if command -v docker-compose &> /dev/null
+then
+ COMPOSE_CMD="docker-compose"
+else
+ COMPOSE_CMD="docker compose"
+fi
+
+restoreData "$@"
\ No newline at end of file
diff --git a/plane/update.sh b/plane/update.sh
new file mode 100644
index 0000000..3bd7313
--- /dev/null
+++ b/plane/update.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+if [ ! -d "./repo" ]; then
+ git clone --depth 1 --branch preview --single-branch https://github.com/makeplane/plane.git repo
+else
+ cd repo
+ git pull
+ cd ..
+fi
+
+cp -r ./repo/deploy/selfhost/. ./code
+mv ./code/variables.env ./code/.env.example
+
+
diff --git a/supabase/update.sh b/supabase/update.sh
index ae4e4dd..24abd5a 100644
--- a/supabase/update.sh
+++ b/supabase/update.sh
@@ -1,6 +1,5 @@
#!/bin/bash
-# check if ./repo exists
if [ ! -d "./repo" ]; then
git clone --depth 1 --branch master --single-branch https://github.com/supabase/supabase repo
else
@@ -9,5 +8,4 @@ else
cd ..
fi
-# copy files from ./repo/docker to ./code
cp -r ./repo/docker/. ./code