-
+
+ {#if !$appSession.whiteLabeled}
+ Coolify
+
+ {:else if $appSession.whiteLabeledDetails.icon}
+ Coolify
+
+ {/if}
+
+
+
+
+
+ {#if $appSession.userId}
+
IAM
+
Settings
+
Documentation
+
Logout
+
+ {#if $appSession.whiteLabeled}
+
Powered by Coolify
+ {/if}
+ {/if}
+
+
+
+
+ {#if !$appSession.whiteLabeled}
+
Coolify
+ {/if}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/client/src/routes/+layout.ts b/apps/client/src/routes/+layout.ts
new file mode 100644
index 000000000..127c1bc08
--- /dev/null
+++ b/apps/client/src/routes/+layout.ts
@@ -0,0 +1,39 @@
+import { error } from '@sveltejs/kit';
+import { t } from '$lib/store';
+import type { LayoutLoad } from './$types';
+import { redirect } from '@sveltejs/kit';
+import Cookies from 'js-cookie';
+export const ssr = false;
+
+export const load: LayoutLoad = async ({ url }) => {
+ const { pathname } = new URL(url);
+ const baseSettings = await t.settings.getBaseSettings.query();
+ try {
+ if (pathname === '/login' || pathname === '/register') {
+ return {
+ ...baseSettings
+ };
+ }
+ const settings = await t.settings.getInstanceSettings.query();
+ if (settings.data.token) {
+ Cookies.set('token', settings.data.token);
+ }
+ return {
+ ...baseSettings,
+ ...settings
+ };
+ } catch (err) {
+ if (err?.data?.httpStatus == 401) {
+ throw redirect(307, '/login');
+ }
+ if (err instanceof Error) {
+ throw error(500, {
+ message: 'An unexpected error occurred, please try again later.' + '
' + err.message
+ });
+ }
+
+ throw error(500, {
+ message: 'An unexpected error occurred, please try again later.'
+ });
+ }
+};
diff --git a/apps/client/src/routes/+page.svelte b/apps/client/src/routes/+page.svelte
index 952613f4d..b3e1c2879 100644
--- a/apps/client/src/routes/+page.svelte
+++ b/apps/client/src/routes/+page.svelte
@@ -1,10 +1,1651 @@
-
hello
+
+
+ {#if applications.length !== 0 || destinations.length !== 0 || databases.length !== 0 || services.length !== 0 || gitSources.length !== 0 || destinations.length !== 0}
+
+
+
+
+
+
+
+
+ {/if}
+ {#if (filtered.applications.length > 0 && applications.length > 0) || filtered.otherApplications.length > 0}
+
+
Applications
+
+ {#if foundUnconfiguredApplication}
+
+ {/if}
+
+ {/if}
+ {#if filtered.applications.length > 0 && applications.length > 0}
+
+
+ {/if}
+ {#if filtered.otherApplications.length > 0}
+ {#if filtered.applications.length > 0}
+
+ {/if}
+ {/if}
+ {#if filtered.otherApplications.length > 0}
+
+ {/if}
+ {#if (filtered.services.length > 0 && services.length > 0) || filtered.otherServices.length > 0}
+
+
Services
+
+ {#if foundUnconfiguredService}
+
+ {/if}
+
+ {/if}
+ {#if filtered.services.length > 0 && services.length > 0}
+
+
+ {/if}
+ {#if filtered.otherServices.length > 0}
+ {#if filtered.services.length > 0}
+
+ {/if}
+ {/if}
+ {#if filtered.otherServices.length > 0}
+
+ {/if}
+ {#if (filtered.databases.length > 0 && databases.length > 0) || filtered.otherDatabases.length > 0}
+
+
Databases
+
+ {#if foundUnconfiguredDatabase}
+
+ {/if}
+
+ {/if}
+ {#if filtered.databases.length > 0 && databases.length > 0}
+
+
+ {/if}
+ {#if filtered.otherDatabases.length > 0}
+ {#if filtered.databases.length > 0}
+
+ {/if}
+ {/if}
+ {#if filtered.otherDatabases.length > 0}
+
+ {/if}
+ {#if (filtered.gitSources.length > 0 && gitSources.length > 0) || filtered.otherGitSources.length > 0}
+
+
Git Sources
+
+ {/if}
+ {#if filtered.gitSources.length > 0 && gitSources.length > 0}
+
+
+ {/if}
+ {#if filtered.otherGitSources.length > 0}
+ {#if filtered.gitSources.length > 0}
+
+ {/if}
+ {/if}
+ {#if filtered.otherGitSources.length > 0}
+
+ {/if}
+ {#if (filtered.destinations.length > 0 && destinations.length > 0) || filtered.otherDestinations.length > 0}
+
+
Destinations
+
+ {/if}
+ {#if filtered.destinations.length > 0 && destinations.length > 0}
+
+
+ {/if}
+ {#if filtered.otherDestinations.length > 0}
+ {#if filtered.destinations.length > 0}
+
+ {/if}
+ {/if}
+ {#if filtered.otherDestinations.length > 0}
+
+ {/if}
+
+ {#if filtered.applications.length === 0 && filtered.destinations.length === 0 && filtered.databases.length === 0 && filtered.services.length === 0 && filtered.gitSources.length === 0 && filtered.destinations.length === 0 && $search}
+
+
+ Nothing found with {$search}.
+
+
+ {/if}
+ {#if applications.length === 0 && destinations.length === 0 && databases.length === 0 && services.length === 0 && gitSources.length === 0 && destinations.length === 0}
+
+
+
+
+ Hey
+
+
It looks like you did not configure anything yet.
+
+
+
+
+ {/if}
+
+
diff --git a/apps/client/src/routes/+page.ts b/apps/client/src/routes/+page.ts
new file mode 100644
index 000000000..00c21903a
--- /dev/null
+++ b/apps/client/src/routes/+page.ts
@@ -0,0 +1,16 @@
+import { error } from '@sveltejs/kit';
+import { t } from '$lib/store';
+import type { LayoutLoad } from './$types';
+import { redirect } from '@sveltejs/kit';
+import Cookies from 'js-cookie';
+export const ssr = false;
+
+export const load: LayoutLoad = async ({ url }) => {
+ try {
+ return await t.dashboard.resources.query();
+ } catch (err) {
+ throw error(500, {
+ message: 'An unexpected error occurred, please try again later.'
+ });
+ }
+};
diff --git a/apps/client/src/routes/login/+page.svelte b/apps/client/src/routes/login/+page.svelte
new file mode 100644
index 000000000..9ee7a3054
--- /dev/null
+++ b/apps/client/src/routes/login/+page.svelte
@@ -0,0 +1,123 @@
+
+
+
+ Login
+
+
+
+
+
Coolify
+ Made self-hosting simple.
+
+
+
+ {#if $appSession.whiteLabeledDetails.icon}
+
+

+
+ {:else}
+
+
+

+
+
+
+
Coolify
+
+ {/if}
+
+
+
+
Welcome back
+ Please login to continue.
+
+
+ {#if browser && window.location.host === 'demo.coolify.io'}
+
+ Registration is open, just fill in an email (does not
+ need to be live email address for the demo instance) and a password.
+
+
+ All users gets an own namespace, so you won't be able
+ to access other users data.
+
+ {/if}
+
+
+
diff --git a/apps/client/src/routes/register/+page.svelte b/apps/client/src/routes/register/+page.svelte
new file mode 100644
index 000000000..2bf9931d8
--- /dev/null
+++ b/apps/client/src/routes/register/+page.svelte
@@ -0,0 +1,146 @@
+
+
+
+
+
Coolify
+ Made self-hosting simple.
+
+
+
+
+
goto('/')}>
+
+
+
+ {#if $appSession.whiteLabeledDetails.icon}
+
+

+
+ {:else}
+
+
+

+
+
+
+
Coolify
+
+ {/if}
+
+
+
+
+
Get started
+ Enter the required fields to complete the registration.
+
+
+ {#if userCount === 0}
+
"First user will be admin."
+ {/if}
+
+
+
diff --git a/apps/client/static/favicon.png b/apps/client/static/favicon.png
index 825b9e65a..2c4482801 100644
Binary files a/apps/client/static/favicon.png and b/apps/client/static/favicon.png differ
diff --git a/apps/client/static/icons/appsmith.png b/apps/client/static/icons/appsmith.png
new file mode 100644
index 000000000..314ad9053
Binary files /dev/null and b/apps/client/static/icons/appsmith.png differ
diff --git a/apps/client/static/icons/appwrite.png b/apps/client/static/icons/appwrite.png
new file mode 100644
index 000000000..2aaa3e1ab
Binary files /dev/null and b/apps/client/static/icons/appwrite.png differ
diff --git a/apps/client/static/icons/compose.png b/apps/client/static/icons/compose.png
new file mode 100644
index 000000000..b9cfb40e1
Binary files /dev/null and b/apps/client/static/icons/compose.png differ
diff --git a/apps/client/static/icons/default.png b/apps/client/static/icons/default.png
new file mode 100644
index 000000000..2c4482801
Binary files /dev/null and b/apps/client/static/icons/default.png differ
diff --git a/apps/client/static/icons/fider.png b/apps/client/static/icons/fider.png
new file mode 100644
index 000000000..6e34acafe
Binary files /dev/null and b/apps/client/static/icons/fider.png differ
diff --git a/apps/client/static/icons/ghost.png b/apps/client/static/icons/ghost.png
new file mode 100644
index 000000000..f4e300654
Binary files /dev/null and b/apps/client/static/icons/ghost.png differ
diff --git a/apps/client/static/icons/gitea.svg b/apps/client/static/icons/gitea.svg
new file mode 100644
index 000000000..87c7c82db
--- /dev/null
+++ b/apps/client/static/icons/gitea.svg
@@ -0,0 +1 @@
+
diff --git a/apps/client/static/icons/glitchtip.svg b/apps/client/static/icons/glitchtip.svg
new file mode 100644
index 000000000..2ae389aae
--- /dev/null
+++ b/apps/client/static/icons/glitchtip.svg
@@ -0,0 +1,46 @@
+
\ No newline at end of file
diff --git a/apps/client/static/icons/grafana.png b/apps/client/static/icons/grafana.png
new file mode 100644
index 000000000..c8659494f
Binary files /dev/null and b/apps/client/static/icons/grafana.png differ
diff --git a/apps/client/static/icons/hasura.png b/apps/client/static/icons/hasura.png
new file mode 100644
index 000000000..30490401e
Binary files /dev/null and b/apps/client/static/icons/hasura.png differ
diff --git a/apps/client/static/icons/keycloak.png b/apps/client/static/icons/keycloak.png
new file mode 100644
index 000000000..8f29f7af7
Binary files /dev/null and b/apps/client/static/icons/keycloak.png differ
diff --git a/apps/client/static/icons/languagetool.svg b/apps/client/static/icons/languagetool.svg
new file mode 100644
index 000000000..fc8cab02f
--- /dev/null
+++ b/apps/client/static/icons/languagetool.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/apps/client/static/icons/lavalink.png b/apps/client/static/icons/lavalink.png
new file mode 100644
index 000000000..114458bf2
Binary files /dev/null and b/apps/client/static/icons/lavalink.png differ
diff --git a/apps/client/static/icons/meilisearch.svg b/apps/client/static/icons/meilisearch.svg
new file mode 100644
index 000000000..72a8f30e1
--- /dev/null
+++ b/apps/client/static/icons/meilisearch.svg
@@ -0,0 +1,40 @@
+
diff --git a/apps/client/static/icons/minio.png b/apps/client/static/icons/minio.png
new file mode 100644
index 000000000..d1b32be9e
Binary files /dev/null and b/apps/client/static/icons/minio.png differ
diff --git a/apps/client/static/icons/moodle.png b/apps/client/static/icons/moodle.png
new file mode 100644
index 000000000..a5cec5be7
Binary files /dev/null and b/apps/client/static/icons/moodle.png differ
diff --git a/apps/client/static/icons/n8n.svg b/apps/client/static/icons/n8n.svg
new file mode 100644
index 000000000..262a6e7a6
--- /dev/null
+++ b/apps/client/static/icons/n8n.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/apps/client/static/icons/nocodb.png b/apps/client/static/icons/nocodb.png
new file mode 100644
index 000000000..dec31a6dd
Binary files /dev/null and b/apps/client/static/icons/nocodb.png differ
diff --git a/apps/client/static/icons/plausibleanalytics.png b/apps/client/static/icons/plausibleanalytics.png
new file mode 100644
index 000000000..c02e68d63
Binary files /dev/null and b/apps/client/static/icons/plausibleanalytics.png differ
diff --git a/apps/client/static/icons/pocketbase.svg b/apps/client/static/icons/pocketbase.svg
new file mode 100644
index 000000000..5b5de956b
--- /dev/null
+++ b/apps/client/static/icons/pocketbase.svg
@@ -0,0 +1,9 @@
+
diff --git a/apps/client/static/icons/searxng.svg b/apps/client/static/icons/searxng.svg
new file mode 100644
index 000000000..c0dd11b43
--- /dev/null
+++ b/apps/client/static/icons/searxng.svg
@@ -0,0 +1,56 @@
+
+
diff --git a/apps/client/static/icons/trilium.png b/apps/client/static/icons/trilium.png
new file mode 100644
index 000000000..249aceef3
Binary files /dev/null and b/apps/client/static/icons/trilium.png differ
diff --git a/apps/client/static/icons/umami.svg b/apps/client/static/icons/umami.svg
new file mode 100644
index 000000000..b9d1abca3
--- /dev/null
+++ b/apps/client/static/icons/umami.svg
@@ -0,0 +1,78 @@
+
diff --git a/apps/client/static/icons/uptimekuma.svg b/apps/client/static/icons/uptimekuma.svg
new file mode 100644
index 000000000..e67bc836a
--- /dev/null
+++ b/apps/client/static/icons/uptimekuma.svg
@@ -0,0 +1,154 @@
+
diff --git a/apps/client/static/icons/vaultwarden.svg b/apps/client/static/icons/vaultwarden.svg
new file mode 100644
index 000000000..15433d8ed
--- /dev/null
+++ b/apps/client/static/icons/vaultwarden.svg
@@ -0,0 +1,30 @@
+
diff --git a/apps/client/static/icons/vscodeserver.png b/apps/client/static/icons/vscodeserver.png
new file mode 100644
index 000000000..37a084767
Binary files /dev/null and b/apps/client/static/icons/vscodeserver.png differ
diff --git a/apps/client/static/icons/weblate.svg b/apps/client/static/icons/weblate.svg
new file mode 100644
index 000000000..99c6ac483
--- /dev/null
+++ b/apps/client/static/icons/weblate.svg
@@ -0,0 +1,56 @@
+
diff --git a/apps/client/static/icons/wordpress.svg b/apps/client/static/icons/wordpress.svg
new file mode 100644
index 000000000..31149e2ba
--- /dev/null
+++ b/apps/client/static/icons/wordpress.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/apps/client/static/poppins-v19-latin-ext_latin_devanagari-500.woff b/apps/client/static/poppins-v19-latin-ext_latin_devanagari-500.woff
new file mode 100644
index 000000000..d5e713b46
Binary files /dev/null and b/apps/client/static/poppins-v19-latin-ext_latin_devanagari-500.woff differ
diff --git a/apps/client/static/poppins-v19-latin-ext_latin_devanagari-500.woff2 b/apps/client/static/poppins-v19-latin-ext_latin_devanagari-500.woff2
new file mode 100644
index 000000000..6e1053fbc
Binary files /dev/null and b/apps/client/static/poppins-v19-latin-ext_latin_devanagari-500.woff2 differ
diff --git a/apps/client/static/poppins-v19-latin-ext_latin_devanagari-regular.woff b/apps/client/static/poppins-v19-latin-ext_latin_devanagari-regular.woff
new file mode 100644
index 000000000..ccce523fe
Binary files /dev/null and b/apps/client/static/poppins-v19-latin-ext_latin_devanagari-regular.woff differ
diff --git a/apps/client/static/poppins-v19-latin-ext_latin_devanagari-regular.woff2 b/apps/client/static/poppins-v19-latin-ext_latin_devanagari-regular.woff2
new file mode 100644
index 000000000..7457692a2
Binary files /dev/null and b/apps/client/static/poppins-v19-latin-ext_latin_devanagari-regular.woff2 differ
diff --git a/apps/client/tailwind.config.cjs b/apps/client/tailwind.config.cjs
index 0f5280a69..cab4ddbb7 100644
--- a/apps/client/tailwind.config.cjs
+++ b/apps/client/tailwind.config.cjs
@@ -1,11 +1,76 @@
-const config = {
- content: ['./src/**/*.{html,js,svelte,ts}'],
+const defaultTheme = require('tailwindcss/defaultTheme');
+module.exports = {
+ content: [
+ './**/*.html',
+ './src/**/*.{js,jsx,ts,tsx,svelte}',
+ './node_modules/flowbite-svelte/**/*.{html,js,svelte,ts}'
+ ],
+ important: true,
+ daisyui: {
+ themes: [
+ {
+ coollabs: {
+ 'base-100': '#323232',
+ 'base-200': '#242424',
+ 'base-300': '#181818',
+ primary: '#6B16ED',
+ 'primary-content': '#fff',
+ secondary: '#343232',
+ accent: '#343232',
+ neutral: '#272626',
+ info: '#0284c7',
+ success: '#16A34A',
+ warning: '#FFFF00',
+ error: '#DC2626',
+ '--rounded-btn': '0.3rem',
+ '--btn-text-case': 'normal'
+ }
+ }
+ ]
+ },
theme: {
+ extend: {
+ keyframes: {
+ wiggle: {
+ '0%, 100%': { transform: 'rotate(-3deg)' },
+ '50%': { transform: 'rotate(3deg)' }
+ }
+ },
+ animation: {
+ wiggle: 'wiggle 0.5s ease-in-out infinite'
+ },
+ fontFamily: {
+ sans: ['Poppins', ...defaultTheme.fontFamily.sans]
+ },
+ colors: {
+ applications: '#16A34A',
+ databases: '#9333EA',
+ 'databases-100': '#9b46ea',
+ destinations: '#0284C7',
+ sources: '#EA580C',
+ services: '#DB2777',
+ settings: '#FEE440',
+ iam: '#C026D3',
+ coollabs: '#6B16ED',
+ 'coollabs-100': '#7317FF',
+ coolblack: '#141414',
+ 'coolgray-100': '#181818',
+ 'coolgray-200': '#202020',
+ 'coolgray-300': '#242424',
+ 'coolgray-400': '#282828',
+ 'coolgray-500': '#323232'
+ }
+ }
+ },
+ variants: {
+ scrollbar: ['dark'],
extend: {}
},
-
- plugins: []
+ darkMode: 'class',
+ plugins: [
+ require('tailwindcss-scrollbar'),
+ require('daisyui'),
+ require('@tailwindcss/typography')
+ ]
};
-
-module.exports = config;
diff --git a/apps/server/.env-template b/apps/server/.env-template
index a45f8578c..d038e068c 100644
--- a/apps/server/.env-template
+++ b/apps/server/.env-template
@@ -1,2 +1,4 @@
NODE_ENV="development"
-DATABASE_URL="file:../db/dev.db"
\ No newline at end of file
+
+COOLIFY_DATABASE_URL="file:../db/dev.db"
+COOLIFY_SECRET_KEY="32-character-long-secret-key"
\ No newline at end of file
diff --git a/apps/server/package.json b/apps/server/package.json
index 0621bd01b..3ce4e8afa 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -16,7 +16,6 @@
"db:migrate": "DATABASE_URL=file:../db/migration.db prisma migrate dev --skip-seed --name"
},
"dependencies": {
- "jsonwebtoken": "8.5.1",
"@fastify/autoload": "5.6.0",
"@fastify/cors": "8.2.0",
"@fastify/env": "4.1.0",
@@ -27,18 +26,31 @@
"@trpc/client": "10.1.0",
"@trpc/server": "10.1.0",
"abort-controller": "3.0.0",
+ "bcryptjs": "2.4.3",
+ "cuid": "2.1.8",
+ "dayjs": "1.11.6",
+ "dotenv": "^16.0.3",
+ "execa": "6.1.0",
"fastify": "4.10.2",
"fastify-plugin": "4.4.0",
+ "got": "^12.5.3",
+ "is-port-reachable": "4.0.0",
+ "jsonwebtoken": "8.5.1",
"node-fetch": "3.3.0",
"prisma": "4.6.1",
+ "shell-quote": "^1.7.4",
+ "ssh-config": "4.1.6",
"superjson": "1.11.0",
"tslib": "2.4.1",
+ "unique-names-generator": "4.7.1",
"ws": "8.11.0",
"zod": "3.19.1"
},
"devDependencies": {
+ "@types/jsonwebtoken": "^8.5.9",
"@types/node": "18.11.9",
"@types/node-fetch": "2.6.2",
+ "@types/shell-quote": "^1.7.1",
"@types/ws": "8.5.3",
"npm-run-all": "4.1.5",
"rimraf": "3.0.2",
diff --git a/apps/server/prisma/migrations/20220131142425_init/migration.sql b/apps/server/prisma/migrations/20220131142425_init/migration.sql
new file mode 100644
index 000000000..6607a48b5
--- /dev/null
+++ b/apps/server/prisma/migrations/20220131142425_init/migration.sql
@@ -0,0 +1,443 @@
+-- CreateTable
+CREATE TABLE "Setting" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "fqdn" TEXT,
+ "isRegistrationEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "proxyPassword" TEXT NOT NULL,
+ "proxyUser" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+
+-- CreateTable
+CREATE TABLE "User" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "email" TEXT NOT NULL,
+ "type" TEXT NOT NULL,
+ "password" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+
+-- CreateTable
+CREATE TABLE "Permission" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "userId" TEXT NOT NULL,
+ "teamId" TEXT NOT NULL,
+ "permission" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Permission_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
+ CONSTRAINT "Permission_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "Team" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "databaseId" TEXT,
+ "serviceId" TEXT,
+ FOREIGN KEY ("databaseId") REFERENCES "Database" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
+ FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "TeamInvitation" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "uid" TEXT NOT NULL,
+ "email" TEXT NOT NULL,
+ "teamId" TEXT NOT NULL,
+ "teamName" TEXT NOT NULL,
+ "permission" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+-- CreateTable
+CREATE TABLE "Application" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "fqdn" TEXT,
+ "repository" TEXT,
+ "configHash" TEXT,
+ "branch" TEXT,
+ "buildPack" TEXT,
+ "projectId" INTEGER,
+ "port" INTEGER,
+ "installCommand" TEXT,
+ "buildCommand" TEXT,
+ "startCommand" TEXT,
+ "baseDirectory" TEXT,
+ "publishDirectory" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "destinationDockerId" TEXT,
+ "gitSourceId" TEXT,
+ CONSTRAINT "Application_destinationDockerId_fkey" FOREIGN KEY ("destinationDockerId") REFERENCES "DestinationDocker" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
+ CONSTRAINT "Application_gitSourceId_fkey" FOREIGN KEY ("gitSourceId") REFERENCES "GitSource" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "ApplicationSettings" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "applicationId" TEXT NOT NULL,
+ "debug" BOOLEAN NOT NULL DEFAULT false,
+ "previews" BOOLEAN NOT NULL DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "ApplicationSettings_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "Secret" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "value" TEXT NOT NULL,
+ "isBuildSecret" BOOLEAN NOT NULL DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "applicationId" TEXT NOT NULL,
+ CONSTRAINT "Secret_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "BuildLog" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "applicationId" TEXT,
+ "buildId" TEXT NOT NULL,
+ "line" TEXT NOT NULL,
+ "time" INTEGER NOT NULL
+);
+
+-- CreateTable
+CREATE TABLE "Build" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "type" TEXT NOT NULL,
+ "applicationId" TEXT,
+ "destinationDockerId" TEXT,
+ "gitSourceId" TEXT,
+ "githubAppId" TEXT,
+ "gitlabAppId" TEXT,
+ "commit" TEXT,
+ "status" TEXT DEFAULT 'queued',
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+
+-- CreateTable
+CREATE TABLE "DestinationDocker" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "network" TEXT NOT NULL,
+ "name" TEXT NOT NULL,
+ "engine" TEXT NOT NULL,
+ "remoteEngine" BOOLEAN NOT NULL DEFAULT false,
+ "isCoolifyProxyUsed" BOOLEAN DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+
+-- CreateTable
+CREATE TABLE "GitSource" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "type" TEXT,
+ "apiUrl" TEXT,
+ "htmlUrl" TEXT,
+ "organization" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "githubAppId" TEXT,
+ "gitlabAppId" TEXT,
+ CONSTRAINT "GitSource_githubAppId_fkey" FOREIGN KEY ("githubAppId") REFERENCES "GithubApp" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
+ CONSTRAINT "GitSource_gitlabAppId_fkey" FOREIGN KEY ("gitlabAppId") REFERENCES "GitlabApp" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "GithubApp" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT,
+ "appId" INTEGER,
+ "installationId" INTEGER,
+ "clientId" TEXT,
+ "clientSecret" TEXT,
+ "webhookSecret" TEXT,
+ "privateKey" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+
+-- CreateTable
+CREATE TABLE "GitlabApp" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "oauthId" INTEGER NOT NULL,
+ "groupName" TEXT,
+ "deployKeyId" INTEGER,
+ "privateSshKey" TEXT,
+ "publicSshKey" TEXT,
+ "webhookToken" TEXT,
+ "appId" TEXT,
+ "appSecret" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+
+-- CreateTable
+CREATE TABLE "Database" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "publicPort" INTEGER,
+ "defaultDatabase" TEXT,
+ "type" TEXT,
+ "version" TEXT,
+ "dbUser" TEXT,
+ "dbUserPassword" TEXT,
+ "rootUser" TEXT,
+ "rootUserPassword" TEXT,
+ "destinationDockerId" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Database_destinationDockerId_fkey" FOREIGN KEY ("destinationDockerId") REFERENCES "DestinationDocker" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "DatabaseSettings" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "databaseId" TEXT NOT NULL,
+ "isPublic" BOOLEAN NOT NULL DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "DatabaseSettings_databaseId_fkey" FOREIGN KEY ("databaseId") REFERENCES "Database" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "Service" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "fqdn" TEXT,
+ "type" TEXT,
+ "version" TEXT,
+ "destinationDockerId" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Service_destinationDockerId_fkey" FOREIGN KEY ("destinationDockerId") REFERENCES "DestinationDocker" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "PlausibleAnalytics" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "email" TEXT,
+ "username" TEXT,
+ "password" TEXT NOT NULL,
+ "postgresqlUser" TEXT NOT NULL,
+ "postgresqlPassword" TEXT NOT NULL,
+ "postgresqlDatabase" TEXT NOT NULL,
+ "postgresqlPublicPort" INTEGER,
+ "secretKeyBase" TEXT,
+ "serviceId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "PlausibleAnalytics_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "Minio" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "rootUser" TEXT NOT NULL,
+ "rootUserPassword" TEXT NOT NULL,
+ "publicPort" INTEGER,
+ "serviceId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Minio_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "Vscodeserver" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "password" TEXT NOT NULL,
+ "serviceId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Vscodeserver_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "Wordpress" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "extraConfig" TEXT,
+ "tablePrefix" TEXT,
+ "mysqlUser" TEXT NOT NULL,
+ "mysqlPassword" TEXT NOT NULL,
+ "mysqlRootUser" TEXT NOT NULL,
+ "mysqlRootUserPassword" TEXT NOT NULL,
+ "mysqlDatabase" TEXT,
+ "mysqlPublicPort" INTEGER,
+ "serviceId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Wordpress_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "_TeamToUser" (
+ "A" TEXT NOT NULL,
+ "B" TEXT NOT NULL,
+ FOREIGN KEY ("A") REFERENCES "Team" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ FOREIGN KEY ("B") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "_ApplicationToTeam" (
+ "A" TEXT NOT NULL,
+ "B" TEXT NOT NULL,
+ FOREIGN KEY ("A") REFERENCES "Application" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ FOREIGN KEY ("B") REFERENCES "Team" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "_GitSourceToTeam" (
+ "A" TEXT NOT NULL,
+ "B" TEXT NOT NULL,
+ FOREIGN KEY ("A") REFERENCES "GitSource" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ FOREIGN KEY ("B") REFERENCES "Team" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "_GithubAppToTeam" (
+ "A" TEXT NOT NULL,
+ "B" TEXT NOT NULL,
+ FOREIGN KEY ("A") REFERENCES "GithubApp" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ FOREIGN KEY ("B") REFERENCES "Team" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "_GitlabAppToTeam" (
+ "A" TEXT NOT NULL,
+ "B" TEXT NOT NULL,
+ FOREIGN KEY ("A") REFERENCES "GitlabApp" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ FOREIGN KEY ("B") REFERENCES "Team" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "_DestinationDockerToTeam" (
+ "A" TEXT NOT NULL,
+ "B" TEXT NOT NULL,
+ FOREIGN KEY ("A") REFERENCES "DestinationDocker" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ FOREIGN KEY ("B") REFERENCES "Team" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "_DatabaseToTeam" (
+ "A" TEXT NOT NULL,
+ "B" TEXT NOT NULL,
+ FOREIGN KEY ("A") REFERENCES "Database" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ FOREIGN KEY ("B") REFERENCES "Team" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "_ServiceToTeam" (
+ "A" TEXT NOT NULL,
+ "B" TEXT NOT NULL,
+ FOREIGN KEY ("A") REFERENCES "Service" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ FOREIGN KEY ("B") REFERENCES "Team" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Setting_fqdn_key" ON "Setting"("fqdn");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "User_id_key" ON "User"("id");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Application_fqdn_key" ON "Application"("fqdn");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "ApplicationSettings_applicationId_key" ON "ApplicationSettings"("applicationId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Secret_name_key" ON "Secret"("name");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "DestinationDocker_network_key" ON "DestinationDocker"("network");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "GitSource_githubAppId_key" ON "GitSource"("githubAppId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "GitSource_gitlabAppId_key" ON "GitSource"("gitlabAppId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "GithubApp_name_key" ON "GithubApp"("name");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "GitlabApp_oauthId_key" ON "GitlabApp"("oauthId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "GitlabApp_groupName_key" ON "GitlabApp"("groupName");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "DatabaseSettings_databaseId_key" ON "DatabaseSettings"("databaseId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "PlausibleAnalytics_serviceId_key" ON "PlausibleAnalytics"("serviceId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Minio_serviceId_key" ON "Minio"("serviceId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Vscodeserver_serviceId_key" ON "Vscodeserver"("serviceId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Wordpress_serviceId_key" ON "Wordpress"("serviceId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "_TeamToUser_AB_unique" ON "_TeamToUser"("A", "B");
+
+-- CreateIndex
+CREATE INDEX "_TeamToUser_B_index" ON "_TeamToUser"("B");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "_ApplicationToTeam_AB_unique" ON "_ApplicationToTeam"("A", "B");
+
+-- CreateIndex
+CREATE INDEX "_ApplicationToTeam_B_index" ON "_ApplicationToTeam"("B");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "_GitSourceToTeam_AB_unique" ON "_GitSourceToTeam"("A", "B");
+
+-- CreateIndex
+CREATE INDEX "_GitSourceToTeam_B_index" ON "_GitSourceToTeam"("B");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "_GithubAppToTeam_AB_unique" ON "_GithubAppToTeam"("A", "B");
+
+-- CreateIndex
+CREATE INDEX "_GithubAppToTeam_B_index" ON "_GithubAppToTeam"("B");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "_GitlabAppToTeam_AB_unique" ON "_GitlabAppToTeam"("A", "B");
+
+-- CreateIndex
+CREATE INDEX "_GitlabAppToTeam_B_index" ON "_GitlabAppToTeam"("B");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "_DestinationDockerToTeam_AB_unique" ON "_DestinationDockerToTeam"("A", "B");
+
+-- CreateIndex
+CREATE INDEX "_DestinationDockerToTeam_B_index" ON "_DestinationDockerToTeam"("B");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "_DatabaseToTeam_AB_unique" ON "_DatabaseToTeam"("A", "B");
+
+-- CreateIndex
+CREATE INDEX "_DatabaseToTeam_B_index" ON "_DatabaseToTeam"("B");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "_ServiceToTeam_AB_unique" ON "_ServiceToTeam"("A", "B");
+
+-- CreateIndex
+CREATE INDEX "_ServiceToTeam_B_index" ON "_ServiceToTeam"("B");
diff --git a/apps/server/prisma/migrations/20220210104005_redis_aol/migration.sql b/apps/server/prisma/migrations/20220210104005_redis_aol/migration.sql
new file mode 100644
index 000000000..8a7e41098
--- /dev/null
+++ b/apps/server/prisma/migrations/20220210104005_redis_aol/migration.sql
@@ -0,0 +1,28 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Team" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "databaseId" TEXT,
+ "serviceId" TEXT
+);
+INSERT INTO "new_Team" ("createdAt", "databaseId", "id", "name", "serviceId", "updatedAt") SELECT "createdAt", "databaseId", "id", "name", "serviceId", "updatedAt" FROM "Team";
+DROP TABLE "Team";
+ALTER TABLE "new_Team" RENAME TO "Team";
+CREATE TABLE "new_DatabaseSettings" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "databaseId" TEXT NOT NULL,
+ "isPublic" BOOLEAN NOT NULL DEFAULT false,
+ "appendOnly" BOOLEAN NOT NULL DEFAULT true,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "DatabaseSettings_databaseId_fkey" FOREIGN KEY ("databaseId") REFERENCES "Database" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_DatabaseSettings" ("createdAt", "databaseId", "id", "isPublic", "updatedAt") SELECT "createdAt", "databaseId", "id", "isPublic", "updatedAt" FROM "DatabaseSettings";
+DROP TABLE "DatabaseSettings";
+ALTER TABLE "new_DatabaseSettings" RENAME TO "DatabaseSettings";
+CREATE UNIQUE INDEX "DatabaseSettings_databaseId_key" ON "DatabaseSettings"("databaseId");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220212142309_unique_secret_by_application/migration.sql b/apps/server/prisma/migrations/20220212142309_unique_secret_by_application/migration.sql
new file mode 100644
index 000000000..da4aa8e7c
--- /dev/null
+++ b/apps/server/prisma/migrations/20220212142309_unique_secret_by_application/migration.sql
@@ -0,0 +1,11 @@
+/*
+ Warnings:
+
+ - A unique constraint covering the columns `[name,applicationId]` on the table `Secret` will be added. If there are existing duplicate values, this will fail.
+
+*/
+-- DropIndex
+DROP INDEX "Secret_name_key";
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Secret_name_applicationId_key" ON "Secret"("name", "applicationId");
diff --git a/apps/server/prisma/migrations/20220217211304_dualcerts/migration.sql b/apps/server/prisma/migrations/20220217211304_dualcerts/migration.sql
new file mode 100644
index 000000000..a6ea0a57d
--- /dev/null
+++ b/apps/server/prisma/migrations/20220217211304_dualcerts/migration.sql
@@ -0,0 +1,47 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Setting" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "fqdn" TEXT,
+ "isRegistrationEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "proxyPassword" TEXT NOT NULL,
+ "proxyUser" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+INSERT INTO "new_Setting" ("createdAt", "fqdn", "id", "isRegistrationEnabled", "proxyPassword", "proxyUser", "updatedAt") SELECT "createdAt", "fqdn", "id", "isRegistrationEnabled", "proxyPassword", "proxyUser", "updatedAt" FROM "Setting";
+DROP TABLE "Setting";
+ALTER TABLE "new_Setting" RENAME TO "Setting";
+CREATE UNIQUE INDEX "Setting_fqdn_key" ON "Setting"("fqdn");
+CREATE TABLE "new_ApplicationSettings" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "applicationId" TEXT NOT NULL,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "debug" BOOLEAN NOT NULL DEFAULT false,
+ "previews" BOOLEAN NOT NULL DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "ApplicationSettings_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_ApplicationSettings" ("applicationId", "createdAt", "debug", "id", "previews", "updatedAt") SELECT "applicationId", "createdAt", "debug", "id", "previews", "updatedAt" FROM "ApplicationSettings";
+DROP TABLE "ApplicationSettings";
+ALTER TABLE "new_ApplicationSettings" RENAME TO "ApplicationSettings";
+CREATE UNIQUE INDEX "ApplicationSettings_applicationId_key" ON "ApplicationSettings"("applicationId");
+CREATE TABLE "new_Service" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "fqdn" TEXT,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "type" TEXT,
+ "version" TEXT,
+ "destinationDockerId" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Service_destinationDockerId_fkey" FOREIGN KEY ("destinationDockerId") REFERENCES "DestinationDocker" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+INSERT INTO "new_Service" ("createdAt", "destinationDockerId", "fqdn", "id", "name", "type", "updatedAt", "version") SELECT "createdAt", "destinationDockerId", "fqdn", "id", "name", "type", "updatedAt", "version" FROM "Service";
+DROP TABLE "Service";
+ALTER TABLE "new_Service" RENAME TO "Service";
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220219231255_prmr_secrets/migration.sql b/apps/server/prisma/migrations/20220219231255_prmr_secrets/migration.sql
new file mode 100644
index 000000000..728fcae36
--- /dev/null
+++ b/apps/server/prisma/migrations/20220219231255_prmr_secrets/migration.sql
@@ -0,0 +1,19 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Secret" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "value" TEXT NOT NULL,
+ "isPRMRSecret" BOOLEAN NOT NULL DEFAULT false,
+ "isBuildSecret" BOOLEAN NOT NULL DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "applicationId" TEXT NOT NULL,
+ CONSTRAINT "Secret_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_Secret" ("applicationId", "createdAt", "id", "isBuildSecret", "name", "updatedAt", "value") SELECT "applicationId", "createdAt", "id", "isBuildSecret", "name", "updatedAt", "value" FROM "Secret";
+DROP TABLE "Secret";
+ALTER TABLE "new_Secret" RENAME TO "Secret";
+CREATE UNIQUE INDEX "Secret_name_applicationId_isPRMRSecret_key" ON "Secret"("name", "applicationId", "isPRMRSecret");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220220141136_public_portrange/migration.sql b/apps/server/prisma/migrations/20220220141136_public_portrange/migration.sql
new file mode 100644
index 000000000..6423e9761
--- /dev/null
+++ b/apps/server/prisma/migrations/20220220141136_public_portrange/migration.sql
@@ -0,0 +1,20 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Setting" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "fqdn" TEXT,
+ "isRegistrationEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "minPort" INTEGER NOT NULL DEFAULT 9000,
+ "maxPort" INTEGER NOT NULL DEFAULT 9100,
+ "proxyPassword" TEXT NOT NULL,
+ "proxyUser" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+INSERT INTO "new_Setting" ("createdAt", "dualCerts", "fqdn", "id", "isRegistrationEnabled", "proxyPassword", "proxyUser", "updatedAt") SELECT "createdAt", "dualCerts", "fqdn", "id", "isRegistrationEnabled", "proxyPassword", "proxyUser", "updatedAt" FROM "Setting";
+DROP TABLE "Setting";
+ALTER TABLE "new_Setting" RENAME TO "Setting";
+CREATE UNIQUE INDEX "Setting_fqdn_key" ON "Setting"("fqdn");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220301101928_proxyhash/migration.sql b/apps/server/prisma/migrations/20220301101928_proxyhash/migration.sql
new file mode 100644
index 000000000..87845b38b
--- /dev/null
+++ b/apps/server/prisma/migrations/20220301101928_proxyhash/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Setting" ADD COLUMN "proxyHash" TEXT;
diff --git a/apps/server/prisma/migrations/20220304141408_service_secrets/migration.sql b/apps/server/prisma/migrations/20220304141408_service_secrets/migration.sql
new file mode 100644
index 000000000..baa0c3f54
--- /dev/null
+++ b/apps/server/prisma/migrations/20220304141408_service_secrets/migration.sql
@@ -0,0 +1,13 @@
+-- CreateTable
+CREATE TABLE "ServiceSecret" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "value" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "serviceId" TEXT NOT NULL,
+ CONSTRAINT "ServiceSecret_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "ServiceSecret_name_serviceId_key" ON "ServiceSecret"("name", "serviceId");
diff --git a/apps/server/prisma/migrations/20220311213422_autodeploy/migration.sql b/apps/server/prisma/migrations/20220311213422_autodeploy/migration.sql
new file mode 100644
index 000000000..d534d9372
--- /dev/null
+++ b/apps/server/prisma/migrations/20220311213422_autodeploy/migration.sql
@@ -0,0 +1,19 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_ApplicationSettings" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "applicationId" TEXT NOT NULL,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "debug" BOOLEAN NOT NULL DEFAULT false,
+ "previews" BOOLEAN NOT NULL DEFAULT false,
+ "autodeploy" BOOLEAN NOT NULL DEFAULT true,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "ApplicationSettings_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_ApplicationSettings" ("applicationId", "createdAt", "debug", "dualCerts", "id", "previews", "updatedAt") SELECT "applicationId", "createdAt", "debug", "dualCerts", "id", "previews", "updatedAt" FROM "ApplicationSettings";
+DROP TABLE "ApplicationSettings";
+ALTER TABLE "new_ApplicationSettings" RENAME TO "ApplicationSettings";
+CREATE UNIQUE INDEX "ApplicationSettings_applicationId_key" ON "ApplicationSettings"("applicationId");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220320141424_phpmodules/migration.sql b/apps/server/prisma/migrations/20220320141424_phpmodules/migration.sql
new file mode 100644
index 000000000..6a17ff8a3
--- /dev/null
+++ b/apps/server/prisma/migrations/20220320141424_phpmodules/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Application" ADD COLUMN "phpModules" TEXT;
diff --git a/apps/server/prisma/migrations/20220322135800_persistent_storage/migration.sql b/apps/server/prisma/migrations/20220322135800_persistent_storage/migration.sql
new file mode 100644
index 000000000..d26ae3f8b
--- /dev/null
+++ b/apps/server/prisma/migrations/20220322135800_persistent_storage/migration.sql
@@ -0,0 +1,18 @@
+-- CreateTable
+CREATE TABLE "ApplicationPersistentStorage" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "applicationId" TEXT NOT NULL,
+ "path" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "ApplicationPersistentStorage_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "ApplicationPersistentStorage_applicationId_key" ON "ApplicationPersistentStorage"("applicationId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "ApplicationPersistentStorage_path_key" ON "ApplicationPersistentStorage"("path");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "ApplicationPersistentStorage_applicationId_path_key" ON "ApplicationPersistentStorage"("applicationId", "path");
diff --git a/apps/server/prisma/migrations/20220327180323_ghost/migration.sql b/apps/server/prisma/migrations/20220327180323_ghost/migration.sql
new file mode 100644
index 000000000..3c1cec36f
--- /dev/null
+++ b/apps/server/prisma/migrations/20220327180323_ghost/migration.sql
@@ -0,0 +1,19 @@
+-- CreateTable
+CREATE TABLE "Ghost" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "defaultEmail" TEXT NOT NULL,
+ "defaultPassword" TEXT NOT NULL,
+ "mariadbUser" TEXT NOT NULL,
+ "mariadbPassword" TEXT NOT NULL,
+ "mariadbRootUser" TEXT NOT NULL,
+ "mariadbRootUserPassword" TEXT NOT NULL,
+ "mariadbDatabase" TEXT,
+ "mariadbPublicPort" INTEGER,
+ "serviceId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Ghost_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Ghost_serviceId_key" ON "Ghost"("serviceId");
diff --git a/apps/server/prisma/migrations/20220402135305_python/migration.sql b/apps/server/prisma/migrations/20220402135305_python/migration.sql
new file mode 100644
index 000000000..0c253d539
--- /dev/null
+++ b/apps/server/prisma/migrations/20220402135305_python/migration.sql
@@ -0,0 +1,4 @@
+-- AlterTable
+ALTER TABLE "Application" ADD COLUMN "pythonModule" TEXT;
+ALTER TABLE "Application" ADD COLUMN "pythonVariable" TEXT;
+ALTER TABLE "Application" ADD COLUMN "pythonWSGI" TEXT;
diff --git a/apps/server/prisma/migrations/20220402210645_meilisearch/migration.sql b/apps/server/prisma/migrations/20220402210645_meilisearch/migration.sql
new file mode 100644
index 000000000..9e832b107
--- /dev/null
+++ b/apps/server/prisma/migrations/20220402210645_meilisearch/migration.sql
@@ -0,0 +1,12 @@
+-- CreateTable
+CREATE TABLE "MeiliSearch" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "masterKey" TEXT NOT NULL,
+ "serviceId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "MeiliSearch_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "MeiliSearch_serviceId_key" ON "MeiliSearch"("serviceId");
diff --git a/apps/server/prisma/migrations/20220405151428_wordpress_sftp/migration.sql b/apps/server/prisma/migrations/20220405151428_wordpress_sftp/migration.sql
new file mode 100644
index 000000000..6c3c4b907
--- /dev/null
+++ b/apps/server/prisma/migrations/20220405151428_wordpress_sftp/migration.sql
@@ -0,0 +1,29 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Wordpress" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "extraConfig" TEXT,
+ "tablePrefix" TEXT,
+ "mysqlUser" TEXT NOT NULL,
+ "mysqlPassword" TEXT NOT NULL,
+ "mysqlRootUser" TEXT NOT NULL,
+ "mysqlRootUserPassword" TEXT NOT NULL,
+ "mysqlDatabase" TEXT,
+ "mysqlPublicPort" INTEGER,
+ "ftpEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "ftpUser" TEXT,
+ "ftpPassword" TEXT,
+ "ftpPublicPort" INTEGER,
+ "ftpHostKey" TEXT,
+ "ftpHostKeyPrivate" TEXT,
+ "serviceId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Wordpress_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_Wordpress" ("createdAt", "extraConfig", "id", "mysqlDatabase", "mysqlPassword", "mysqlPublicPort", "mysqlRootUser", "mysqlRootUserPassword", "mysqlUser", "serviceId", "tablePrefix", "updatedAt") SELECT "createdAt", "extraConfig", "id", "mysqlDatabase", "mysqlPassword", "mysqlPublicPort", "mysqlRootUser", "mysqlRootUserPassword", "mysqlUser", "serviceId", "tablePrefix", "updatedAt" FROM "Wordpress";
+DROP TABLE "Wordpress";
+ALTER TABLE "new_Wordpress" RENAME TO "Wordpress";
+CREATE UNIQUE INDEX "Wordpress_serviceId_key" ON "Wordpress"("serviceId");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220407220809_unique_storage_fix/migration.sql b/apps/server/prisma/migrations/20220407220809_unique_storage_fix/migration.sql
new file mode 100644
index 000000000..9b645cc3b
--- /dev/null
+++ b/apps/server/prisma/migrations/20220407220809_unique_storage_fix/migration.sql
@@ -0,0 +1,5 @@
+-- DropIndex
+DROP INDEX "ApplicationPersistentStorage_path_key";
+
+-- DropIndex
+DROP INDEX "ApplicationPersistentStorage_applicationId_key";
diff --git a/apps/server/prisma/migrations/20220408070805_added_expose_port/migration.sql b/apps/server/prisma/migrations/20220408070805_added_expose_port/migration.sql
new file mode 100644
index 000000000..a23afd64a
--- /dev/null
+++ b/apps/server/prisma/migrations/20220408070805_added_expose_port/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Application" ADD COLUMN "exposePort" INTEGER;
diff --git a/apps/server/prisma/migrations/20220418214843_persistent_storage_services/migration.sql b/apps/server/prisma/migrations/20220418214843_persistent_storage_services/migration.sql
new file mode 100644
index 000000000..f85fd31df
--- /dev/null
+++ b/apps/server/prisma/migrations/20220418214843_persistent_storage_services/migration.sql
@@ -0,0 +1,12 @@
+-- CreateTable
+CREATE TABLE "ServicePersistentStorage" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "serviceId" TEXT NOT NULL,
+ "path" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "ServicePersistentStorage_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "ServicePersistentStorage_serviceId_path_key" ON "ServicePersistentStorage"("serviceId", "path");
diff --git a/apps/server/prisma/migrations/20220419203408_multiply_dockerfile_locations/migration.sql b/apps/server/prisma/migrations/20220419203408_multiply_dockerfile_locations/migration.sql
new file mode 100644
index 000000000..ce32f0844
--- /dev/null
+++ b/apps/server/prisma/migrations/20220419203408_multiply_dockerfile_locations/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Application" ADD COLUMN "dockerFileLocation" TEXT;
diff --git a/apps/server/prisma/migrations/20220420202031_deno_configurations/migration.sql b/apps/server/prisma/migrations/20220420202031_deno_configurations/migration.sql
new file mode 100644
index 000000000..9d0e832dc
--- /dev/null
+++ b/apps/server/prisma/migrations/20220420202031_deno_configurations/migration.sql
@@ -0,0 +1,3 @@
+-- AlterTable
+ALTER TABLE "Application" ADD COLUMN "denoMainFile" TEXT;
+ALTER TABLE "Application" ADD COLUMN "denoOptions" TEXT;
diff --git a/apps/server/prisma/migrations/20220420210057_branch_for_builds/migration.sql b/apps/server/prisma/migrations/20220420210057_branch_for_builds/migration.sql
new file mode 100644
index 000000000..8cd8e653d
--- /dev/null
+++ b/apps/server/prisma/migrations/20220420210057_branch_for_builds/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Build" ADD COLUMN "branch" TEXT;
diff --git a/apps/server/prisma/migrations/20220425071132_umami/migration.sql b/apps/server/prisma/migrations/20220425071132_umami/migration.sql
new file mode 100644
index 000000000..259fb76cd
--- /dev/null
+++ b/apps/server/prisma/migrations/20220425071132_umami/migration.sql
@@ -0,0 +1,17 @@
+-- CreateTable
+CREATE TABLE "Umami" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "serviceId" TEXT NOT NULL,
+ "postgresqlUser" TEXT NOT NULL,
+ "postgresqlPassword" TEXT NOT NULL,
+ "postgresqlDatabase" TEXT NOT NULL,
+ "postgresqlPublicPort" INTEGER,
+ "umamiAdminPassword" TEXT NOT NULL,
+ "hashSalt" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Umami_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Umami_serviceId_key" ON "Umami"("serviceId");
diff --git a/apps/server/prisma/migrations/20220425075326_auto_update_coolify/migration.sql b/apps/server/prisma/migrations/20220425075326_auto_update_coolify/migration.sql
new file mode 100644
index 000000000..a102973ee
--- /dev/null
+++ b/apps/server/prisma/migrations/20220425075326_auto_update_coolify/migration.sql
@@ -0,0 +1,22 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Setting" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "fqdn" TEXT,
+ "isRegistrationEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "minPort" INTEGER NOT NULL DEFAULT 9000,
+ "maxPort" INTEGER NOT NULL DEFAULT 9100,
+ "proxyPassword" TEXT NOT NULL,
+ "proxyUser" TEXT NOT NULL,
+ "proxyHash" TEXT,
+ "isAutoUpdateEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+INSERT INTO "new_Setting" ("createdAt", "dualCerts", "fqdn", "id", "isRegistrationEnabled", "maxPort", "minPort", "proxyHash", "proxyPassword", "proxyUser", "updatedAt") SELECT "createdAt", "dualCerts", "fqdn", "id", "isRegistrationEnabled", "maxPort", "minPort", "proxyHash", "proxyPassword", "proxyUser", "updatedAt" FROM "Setting";
+DROP TABLE "Setting";
+ALTER TABLE "new_Setting" RENAME TO "Setting";
+CREATE UNIQUE INDEX "Setting_fqdn_key" ON "Setting"("fqdn");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220426125053_select_base_image/migration.sql b/apps/server/prisma/migrations/20220426125053_select_base_image/migration.sql
new file mode 100644
index 000000000..37209d82f
--- /dev/null
+++ b/apps/server/prisma/migrations/20220426125053_select_base_image/migration.sql
@@ -0,0 +1,3 @@
+-- AlterTable
+ALTER TABLE "Application" ADD COLUMN "baseBuildImage" TEXT;
+ALTER TABLE "Application" ADD COLUMN "baseImage" TEXT;
diff --git a/apps/server/prisma/migrations/20220427133656_hasura/migration.sql b/apps/server/prisma/migrations/20220427133656_hasura/migration.sql
new file mode 100644
index 000000000..c679ad0fb
--- /dev/null
+++ b/apps/server/prisma/migrations/20220427133656_hasura/migration.sql
@@ -0,0 +1,16 @@
+-- CreateTable
+CREATE TABLE "Hasura" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "serviceId" TEXT NOT NULL,
+ "postgresqlUser" TEXT NOT NULL,
+ "postgresqlPassword" TEXT NOT NULL,
+ "postgresqlDatabase" TEXT NOT NULL,
+ "postgresqlPublicPort" INTEGER,
+ "graphQLAdminPassword" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Hasura_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Hasura_serviceId_key" ON "Hasura"("serviceId");
diff --git a/apps/server/prisma/migrations/20220429202516_fider/migration.sql b/apps/server/prisma/migrations/20220429202516_fider/migration.sql
new file mode 100644
index 000000000..a6d31a24d
--- /dev/null
+++ b/apps/server/prisma/migrations/20220429202516_fider/migration.sql
@@ -0,0 +1,25 @@
+-- CreateTable
+CREATE TABLE "Fider" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "serviceId" TEXT NOT NULL,
+ "postgresqlUser" TEXT NOT NULL,
+ "postgresqlPassword" TEXT NOT NULL,
+ "postgresqlDatabase" TEXT NOT NULL,
+ "postgresqlPublicPort" INTEGER,
+ "jwtSecret" TEXT NOT NULL,
+ "emailNoreply" TEXT,
+ "emailMailgunApiKey" TEXT,
+ "emailMailgunDomain" TEXT,
+ "emailMailgunRegion" TEXT,
+ "emailSmtpHost" TEXT,
+ "emailSmtpPort" INTEGER,
+ "emailSmtpUser" TEXT,
+ "emailSmtpPassword" TEXT,
+ "emailSmtpEnableStartTls" BOOLEAN NOT NULL DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Fider_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Fider_serviceId_key" ON "Fider"("serviceId");
diff --git a/apps/server/prisma/migrations/20220429214112_fider_correction/migration.sql b/apps/server/prisma/migrations/20220429214112_fider_correction/migration.sql
new file mode 100644
index 000000000..429524f72
--- /dev/null
+++ b/apps/server/prisma/migrations/20220429214112_fider_correction/migration.sql
@@ -0,0 +1,29 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Fider" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "serviceId" TEXT NOT NULL,
+ "postgresqlUser" TEXT NOT NULL,
+ "postgresqlPassword" TEXT NOT NULL,
+ "postgresqlDatabase" TEXT NOT NULL,
+ "postgresqlPublicPort" INTEGER,
+ "jwtSecret" TEXT NOT NULL,
+ "emailNoreply" TEXT,
+ "emailMailgunApiKey" TEXT,
+ "emailMailgunDomain" TEXT,
+ "emailMailgunRegion" TEXT NOT NULL DEFAULT 'EU',
+ "emailSmtpHost" TEXT,
+ "emailSmtpPort" INTEGER,
+ "emailSmtpUser" TEXT,
+ "emailSmtpPassword" TEXT,
+ "emailSmtpEnableStartTls" BOOLEAN NOT NULL DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Fider_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_Fider" ("createdAt", "emailMailgunApiKey", "emailMailgunDomain", "emailMailgunRegion", "emailNoreply", "emailSmtpEnableStartTls", "emailSmtpHost", "emailSmtpPassword", "emailSmtpPort", "emailSmtpUser", "id", "jwtSecret", "postgresqlDatabase", "postgresqlPassword", "postgresqlPublicPort", "postgresqlUser", "serviceId", "updatedAt") SELECT "createdAt", "emailMailgunApiKey", "emailMailgunDomain", coalesce("emailMailgunRegion", 'EU') AS "emailMailgunRegion", "emailNoreply", "emailSmtpEnableStartTls", "emailSmtpHost", "emailSmtpPassword", "emailSmtpPort", "emailSmtpUser", "id", "jwtSecret", "postgresqlDatabase", "postgresqlPassword", "postgresqlPublicPort", "postgresqlUser", "serviceId", "updatedAt" FROM "Fider";
+DROP TABLE "Fider";
+ALTER TABLE "new_Fider" RENAME TO "Fider";
+CREATE UNIQUE INDEX "Fider_serviceId_key" ON "Fider"("serviceId");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220430111953_ssl_dns_check_settings/migration.sql b/apps/server/prisma/migrations/20220430111953_ssl_dns_check_settings/migration.sql
new file mode 100644
index 000000000..cf57379ca
--- /dev/null
+++ b/apps/server/prisma/migrations/20220430111953_ssl_dns_check_settings/migration.sql
@@ -0,0 +1,23 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Setting" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "fqdn" TEXT,
+ "isRegistrationEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "minPort" INTEGER NOT NULL DEFAULT 9000,
+ "maxPort" INTEGER NOT NULL DEFAULT 9100,
+ "proxyPassword" TEXT NOT NULL,
+ "proxyUser" TEXT NOT NULL,
+ "proxyHash" TEXT,
+ "isAutoUpdateEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "isDNSCheckEnabled" BOOLEAN NOT NULL DEFAULT true,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+INSERT INTO "new_Setting" ("createdAt", "dualCerts", "fqdn", "id", "isAutoUpdateEnabled", "isRegistrationEnabled", "maxPort", "minPort", "proxyHash", "proxyPassword", "proxyUser", "updatedAt") SELECT "createdAt", "dualCerts", "fqdn", "id", "isAutoUpdateEnabled", "isRegistrationEnabled", "maxPort", "minPort", "proxyHash", "proxyPassword", "proxyUser", "updatedAt" FROM "Setting";
+DROP TABLE "Setting";
+ALTER TABLE "new_Setting" RENAME TO "Setting";
+CREATE UNIQUE INDEX "Setting_fqdn_key" ON "Setting"("fqdn");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220430124553_expose_port_for_services/migration.sql b/apps/server/prisma/migrations/20220430124553_expose_port_for_services/migration.sql
new file mode 100644
index 000000000..fdbab5713
--- /dev/null
+++ b/apps/server/prisma/migrations/20220430124553_expose_port_for_services/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Service" ADD COLUMN "exposePort" INTEGER;
diff --git a/apps/server/prisma/migrations/20220509130501_custom_plausible_script/migration.sql b/apps/server/prisma/migrations/20220509130501_custom_plausible_script/migration.sql
new file mode 100644
index 000000000..6c8c28ff4
--- /dev/null
+++ b/apps/server/prisma/migrations/20220509130501_custom_plausible_script/migration.sql
@@ -0,0 +1,24 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_PlausibleAnalytics" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "email" TEXT,
+ "username" TEXT,
+ "password" TEXT NOT NULL,
+ "postgresqlUser" TEXT NOT NULL,
+ "postgresqlPassword" TEXT NOT NULL,
+ "postgresqlDatabase" TEXT NOT NULL,
+ "postgresqlPublicPort" INTEGER,
+ "secretKeyBase" TEXT,
+ "scriptName" TEXT NOT NULL DEFAULT 'plausible.js',
+ "serviceId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "PlausibleAnalytics_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_PlausibleAnalytics" ("createdAt", "email", "id", "password", "postgresqlDatabase", "postgresqlPassword", "postgresqlPublicPort", "postgresqlUser", "secretKeyBase", "serviceId", "updatedAt", "username") SELECT "createdAt", "email", "id", "password", "postgresqlDatabase", "postgresqlPassword", "postgresqlPublicPort", "postgresqlUser", "secretKeyBase", "serviceId", "updatedAt", "username" FROM "PlausibleAnalytics";
+DROP TABLE "PlausibleAnalytics";
+ALTER TABLE "new_PlausibleAnalytics" RENAME TO "PlausibleAnalytics";
+CREATE UNIQUE INDEX "PlausibleAnalytics_serviceId_key" ON "PlausibleAnalytics"("serviceId");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220510081125_custom_wordpress_db/migration.sql b/apps/server/prisma/migrations/20220510081125_custom_wordpress_db/migration.sql
new file mode 100644
index 000000000..5a1cd301c
--- /dev/null
+++ b/apps/server/prisma/migrations/20220510081125_custom_wordpress_db/migration.sql
@@ -0,0 +1,32 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Wordpress" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "extraConfig" TEXT,
+ "tablePrefix" TEXT,
+ "ownMysql" BOOLEAN NOT NULL DEFAULT false,
+ "mysqlHost" TEXT,
+ "mysqlPort" INTEGER,
+ "mysqlUser" TEXT NOT NULL,
+ "mysqlPassword" TEXT NOT NULL,
+ "mysqlRootUser" TEXT NOT NULL,
+ "mysqlRootUserPassword" TEXT NOT NULL,
+ "mysqlDatabase" TEXT,
+ "mysqlPublicPort" INTEGER,
+ "ftpEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "ftpUser" TEXT,
+ "ftpPassword" TEXT,
+ "ftpPublicPort" INTEGER,
+ "ftpHostKey" TEXT,
+ "ftpHostKeyPrivate" TEXT,
+ "serviceId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Wordpress_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_Wordpress" ("createdAt", "extraConfig", "ftpEnabled", "ftpHostKey", "ftpHostKeyPrivate", "ftpPassword", "ftpPublicPort", "ftpUser", "id", "mysqlDatabase", "mysqlPassword", "mysqlPublicPort", "mysqlRootUser", "mysqlRootUserPassword", "mysqlUser", "serviceId", "tablePrefix", "updatedAt") SELECT "createdAt", "extraConfig", "ftpEnabled", "ftpHostKey", "ftpHostKeyPrivate", "ftpPassword", "ftpPublicPort", "ftpUser", "id", "mysqlDatabase", "mysqlPassword", "mysqlPublicPort", "mysqlRootUser", "mysqlRootUserPassword", "mysqlUser", "serviceId", "tablePrefix", "updatedAt" FROM "Wordpress";
+DROP TABLE "Wordpress";
+ALTER TABLE "new_Wordpress" RENAME TO "Wordpress";
+CREATE UNIQUE INDEX "Wordpress_serviceId_key" ON "Wordpress"("serviceId");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220517081328_traefik/migration.sql b/apps/server/prisma/migrations/20220517081328_traefik/migration.sql
new file mode 100644
index 000000000..a83281fa4
--- /dev/null
+++ b/apps/server/prisma/migrations/20220517081328_traefik/migration.sql
@@ -0,0 +1,24 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Setting" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "fqdn" TEXT,
+ "isRegistrationEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "minPort" INTEGER NOT NULL DEFAULT 9000,
+ "maxPort" INTEGER NOT NULL DEFAULT 9100,
+ "proxyPassword" TEXT NOT NULL,
+ "proxyUser" TEXT NOT NULL,
+ "proxyHash" TEXT,
+ "isAutoUpdateEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "isDNSCheckEnabled" BOOLEAN NOT NULL DEFAULT true,
+ "isTraefikUsed" BOOLEAN NOT NULL DEFAULT true,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+INSERT INTO "new_Setting" ("createdAt", "dualCerts", "fqdn", "id", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "maxPort", "minPort", "proxyHash", "proxyPassword", "proxyUser", "updatedAt") SELECT "createdAt", "dualCerts", "fqdn", "id", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "maxPort", "minPort", "proxyHash", "proxyPassword", "proxyUser", "updatedAt" FROM "Setting";
+DROP TABLE "Setting";
+ALTER TABLE "new_Setting" RENAME TO "Setting";
+CREATE UNIQUE INDEX "Setting_fqdn_key" ON "Setting"("fqdn");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220519095648_minio_apifqdn/migration.sql b/apps/server/prisma/migrations/20220519095648_minio_apifqdn/migration.sql
new file mode 100644
index 000000000..a44712864
--- /dev/null
+++ b/apps/server/prisma/migrations/20220519095648_minio_apifqdn/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Minio" ADD COLUMN "apiFqdn" TEXT;
diff --git a/apps/server/prisma/migrations/20220708132655_deployment_type_for_applications/migration.sql b/apps/server/prisma/migrations/20220708132655_deployment_type_for_applications/migration.sql
new file mode 100644
index 000000000..2776d1b88
--- /dev/null
+++ b/apps/server/prisma/migrations/20220708132655_deployment_type_for_applications/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Application" ADD COLUMN "deploymentType" TEXT;
diff --git a/apps/server/prisma/migrations/20220712083523_custom_port_git_sources/migration.sql b/apps/server/prisma/migrations/20220712083523_custom_port_git_sources/migration.sql
new file mode 100644
index 000000000..f702291b2
--- /dev/null
+++ b/apps/server/prisma/migrations/20220712083523_custom_port_git_sources/migration.sql
@@ -0,0 +1,24 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_GitSource" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "type" TEXT,
+ "apiUrl" TEXT,
+ "htmlUrl" TEXT,
+ "customPort" INTEGER NOT NULL DEFAULT 22,
+ "organization" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "githubAppId" TEXT,
+ "gitlabAppId" TEXT,
+ CONSTRAINT "GitSource_githubAppId_fkey" FOREIGN KEY ("githubAppId") REFERENCES "GithubApp" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
+ CONSTRAINT "GitSource_gitlabAppId_fkey" FOREIGN KEY ("gitlabAppId") REFERENCES "GitlabApp" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+INSERT INTO "new_GitSource" ("apiUrl", "createdAt", "githubAppId", "gitlabAppId", "htmlUrl", "id", "name", "organization", "type", "updatedAt") SELECT "apiUrl", "createdAt", "githubAppId", "gitlabAppId", "htmlUrl", "id", "name", "organization", "type", "updatedAt" FROM "GitSource";
+DROP TABLE "GitSource";
+ALTER TABLE "new_GitSource" RENAME TO "GitSource";
+CREATE UNIQUE INDEX "GitSource_githubAppId_key" ON "GitSource"("githubAppId");
+CREATE UNIQUE INDEX "GitSource_gitlabAppId_key" ON "GitSource"("gitlabAppId");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220718083646_moodle/migration.sql b/apps/server/prisma/migrations/20220718083646_moodle/migration.sql
new file mode 100644
index 000000000..eaed14a4a
--- /dev/null
+++ b/apps/server/prisma/migrations/20220718083646_moodle/migration.sql
@@ -0,0 +1,20 @@
+-- CreateTable
+CREATE TABLE "Moodle" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "serviceId" TEXT NOT NULL,
+ "defaultUsername" TEXT NOT NULL,
+ "defaultPassword" TEXT NOT NULL,
+ "defaultEmail" TEXT NOT NULL,
+ "mariadbUser" TEXT NOT NULL,
+ "mariadbPassword" TEXT NOT NULL,
+ "mariadbRootUser" TEXT NOT NULL,
+ "mariadbRootUserPassword" TEXT NOT NULL,
+ "mariadbDatabase" TEXT NOT NULL,
+ "mariadbPublicPort" INTEGER,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Moodle_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Moodle_serviceId_key" ON "Moodle"("serviceId");
diff --git a/apps/server/prisma/migrations/20220718114551_remote_docker_engine/migration.sql b/apps/server/prisma/migrations/20220718114551_remote_docker_engine/migration.sql
new file mode 100644
index 000000000..e80df22f2
--- /dev/null
+++ b/apps/server/prisma/migrations/20220718114551_remote_docker_engine/migration.sql
@@ -0,0 +1,21 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_DestinationDocker" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "network" TEXT NOT NULL,
+ "name" TEXT NOT NULL,
+ "engine" TEXT,
+ "remoteEngine" BOOLEAN NOT NULL DEFAULT false,
+ "remoteIpAddress" TEXT,
+ "remoteUser" TEXT,
+ "remotePort" INTEGER,
+ "isCoolifyProxyUsed" BOOLEAN DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+INSERT INTO "new_DestinationDocker" ("createdAt", "engine", "id", "isCoolifyProxyUsed", "name", "network", "remoteEngine", "updatedAt") SELECT "createdAt", "engine", "id", "isCoolifyProxyUsed", "name", "network", "remoteEngine", "updatedAt" FROM "DestinationDocker";
+DROP TABLE "DestinationDocker";
+ALTER TABLE "new_DestinationDocker" RENAME TO "DestinationDocker";
+CREATE UNIQUE INDEX "DestinationDocker_network_key" ON "DestinationDocker"("network");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220721084020_ssh_key/migration.sql b/apps/server/prisma/migrations/20220721084020_ssh_key/migration.sql
new file mode 100644
index 000000000..8323af409
--- /dev/null
+++ b/apps/server/prisma/migrations/20220721084020_ssh_key/migration.sql
@@ -0,0 +1,33 @@
+-- CreateTable
+CREATE TABLE "SshKey" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "privateKey" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_DestinationDocker" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "network" TEXT NOT NULL,
+ "name" TEXT NOT NULL,
+ "engine" TEXT,
+ "remoteEngine" BOOLEAN NOT NULL DEFAULT false,
+ "remoteIpAddress" TEXT,
+ "remoteUser" TEXT,
+ "remotePort" INTEGER,
+ "remoteVerified" BOOLEAN NOT NULL DEFAULT false,
+ "isCoolifyProxyUsed" BOOLEAN DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "sshKeyId" TEXT,
+ CONSTRAINT "DestinationDocker_sshKeyId_fkey" FOREIGN KEY ("sshKeyId") REFERENCES "SshKey" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+INSERT INTO "new_DestinationDocker" ("createdAt", "engine", "id", "isCoolifyProxyUsed", "name", "network", "remoteEngine", "remoteIpAddress", "remotePort", "remoteUser", "updatedAt") SELECT "createdAt", "engine", "id", "isCoolifyProxyUsed", "name", "network", "remoteEngine", "remoteIpAddress", "remotePort", "remoteUser", "updatedAt" FROM "DestinationDocker";
+DROP TABLE "DestinationDocker";
+ALTER TABLE "new_DestinationDocker" RENAME TO "DestinationDocker";
+CREATE UNIQUE INDEX "DestinationDocker_network_key" ON "DestinationDocker"("network");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220722203927_ipaddress/migration.sql b/apps/server/prisma/migrations/20220722203927_ipaddress/migration.sql
new file mode 100644
index 000000000..21d45ada3
--- /dev/null
+++ b/apps/server/prisma/migrations/20220722203927_ipaddress/migration.sql
@@ -0,0 +1,3 @@
+-- AlterTable
+ALTER TABLE "Setting" ADD COLUMN "ipv4" TEXT;
+ALTER TABLE "Setting" ADD COLUMN "ipv6" TEXT;
diff --git a/apps/server/prisma/migrations/20220725191205_architecture/migration.sql b/apps/server/prisma/migrations/20220725191205_architecture/migration.sql
new file mode 100644
index 000000000..2e0ff3e01
--- /dev/null
+++ b/apps/server/prisma/migrations/20220725191205_architecture/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Setting" ADD COLUMN "arch" TEXT;
diff --git a/apps/server/prisma/migrations/20220726121333_fix_ssh_key/migration.sql b/apps/server/prisma/migrations/20220726121333_fix_ssh_key/migration.sql
new file mode 100644
index 000000000..e6e47b197
--- /dev/null
+++ b/apps/server/prisma/migrations/20220726121333_fix_ssh_key/migration.sql
@@ -0,0 +1,16 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_SshKey" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "privateKey" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "teamId" TEXT,
+ CONSTRAINT "SshKey_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+INSERT INTO "new_SshKey" ("createdAt", "id", "name", "privateKey", "updatedAt") SELECT "createdAt", "id", "name", "privateKey", "updatedAt" FROM "SshKey";
+DROP TABLE "SshKey";
+ALTER TABLE "new_SshKey" RENAME TO "SshKey";
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220806090621_fqdn_not_unique_anymore/migration.sql b/apps/server/prisma/migrations/20220806090621_fqdn_not_unique_anymore/migration.sql
new file mode 100644
index 000000000..f1eab666b
--- /dev/null
+++ b/apps/server/prisma/migrations/20220806090621_fqdn_not_unique_anymore/migration.sql
@@ -0,0 +1,2 @@
+-- DropIndex
+DROP INDEX "Application_fqdn_key";
diff --git a/apps/server/prisma/migrations/20220806102340_rde_ssh_local_port/migration.sql b/apps/server/prisma/migrations/20220806102340_rde_ssh_local_port/migration.sql
new file mode 100644
index 000000000..ae4c39846
--- /dev/null
+++ b/apps/server/prisma/migrations/20220806102340_rde_ssh_local_port/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "DestinationDocker" ADD COLUMN "sshLocalPort" INTEGER;
diff --git a/apps/server/prisma/migrations/20220815092230_glitchtip/migration.sql b/apps/server/prisma/migrations/20220815092230_glitchtip/migration.sql
new file mode 100644
index 000000000..dba98ab82
--- /dev/null
+++ b/apps/server/prisma/migrations/20220815092230_glitchtip/migration.sql
@@ -0,0 +1,30 @@
+-- CreateTable
+CREATE TABLE "GlitchTip" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "postgresqlUser" TEXT NOT NULL,
+ "postgresqlPassword" TEXT NOT NULL,
+ "postgresqlDatabase" TEXT NOT NULL,
+ "postgresqlPublicPort" INTEGER,
+ "secretKeyBase" TEXT,
+ "defaultEmail" TEXT NOT NULL,
+ "defaultUsername" TEXT NOT NULL,
+ "defaultPassword" TEXT NOT NULL,
+ "defaultEmailFrom" TEXT NOT NULL DEFAULT 'glitchtip@domain.tdl',
+ "emailSmtpHost" TEXT DEFAULT 'domain.tdl',
+ "emailSmtpPort" INTEGER DEFAULT 25,
+ "emailSmtpUser" TEXT,
+ "emailSmtpPassword" TEXT,
+ "emailSmtpUseTls" BOOLEAN DEFAULT false,
+ "emailSmtpUseSsl" BOOLEAN DEFAULT false,
+ "emailBackend" TEXT,
+ "mailgunApiKey" TEXT,
+ "sendgridApiKey" TEXT,
+ "enableOpenUserRegistration" BOOLEAN NOT NULL DEFAULT true,
+ "serviceId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "GlitchTip_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "GlitchTip_serviceId_key" ON "GlitchTip"("serviceId");
diff --git a/apps/server/prisma/migrations/20220815133844_appwrite/migration.sql b/apps/server/prisma/migrations/20220815133844_appwrite/migration.sql
new file mode 100644
index 000000000..ec61dc434
--- /dev/null
+++ b/apps/server/prisma/migrations/20220815133844_appwrite/migration.sql
@@ -0,0 +1,22 @@
+-- CreateTable
+CREATE TABLE "Appwrite" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "serviceId" TEXT NOT NULL,
+ "opensslKeyV1" TEXT NOT NULL,
+ "executorSecret" TEXT NOT NULL,
+ "redisPassword" TEXT NOT NULL,
+ "mariadbHost" TEXT,
+ "mariadbPort" INTEGER NOT NULL DEFAULT 3306,
+ "mariadbUser" TEXT NOT NULL,
+ "mariadbPassword" TEXT NOT NULL,
+ "mariadbRootUser" TEXT NOT NULL,
+ "mariadbRootUserPassword" TEXT NOT NULL,
+ "mariadbDatabase" TEXT NOT NULL,
+ "mariadbPublicPort" INTEGER,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Appwrite_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Appwrite_serviceId_key" ON "Appwrite"("serviceId");
diff --git a/apps/server/prisma/migrations/20220816133447_bot_deployments/migration.sql b/apps/server/prisma/migrations/20220816133447_bot_deployments/migration.sql
new file mode 100644
index 000000000..3d6d92d0e
--- /dev/null
+++ b/apps/server/prisma/migrations/20220816133447_bot_deployments/migration.sql
@@ -0,0 +1,20 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_ApplicationSettings" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "applicationId" TEXT NOT NULL,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "debug" BOOLEAN NOT NULL DEFAULT false,
+ "previews" BOOLEAN NOT NULL DEFAULT false,
+ "autodeploy" BOOLEAN NOT NULL DEFAULT true,
+ "isBot" BOOLEAN NOT NULL DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "ApplicationSettings_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_ApplicationSettings" ("applicationId", "autodeploy", "createdAt", "debug", "dualCerts", "id", "previews", "updatedAt") SELECT "applicationId", "autodeploy", "createdAt", "debug", "dualCerts", "id", "previews", "updatedAt" FROM "ApplicationSettings";
+DROP TABLE "ApplicationSettings";
+ALTER TABLE "new_ApplicationSettings" RENAME TO "ApplicationSettings";
+CREATE UNIQUE INDEX "ApplicationSettings_applicationId_key" ON "ApplicationSettings"("applicationId");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220817082342_custom_dns_servers/migration.sql b/apps/server/prisma/migrations/20220817082342_custom_dns_servers/migration.sql
new file mode 100644
index 000000000..03588b549
--- /dev/null
+++ b/apps/server/prisma/migrations/20220817082342_custom_dns_servers/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Setting" ADD COLUMN "DNSServers" TEXT;
diff --git a/apps/server/prisma/migrations/20220818093615_public_repositories/migration.sql b/apps/server/prisma/migrations/20220818093615_public_repositories/migration.sql
new file mode 100644
index 000000000..7f08c29fd
--- /dev/null
+++ b/apps/server/prisma/migrations/20220818093615_public_repositories/migration.sql
@@ -0,0 +1,42 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_GitSource" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "forPublic" BOOLEAN NOT NULL DEFAULT false,
+ "type" TEXT,
+ "apiUrl" TEXT,
+ "htmlUrl" TEXT,
+ "customPort" INTEGER NOT NULL DEFAULT 22,
+ "organization" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "githubAppId" TEXT,
+ "gitlabAppId" TEXT,
+ CONSTRAINT "GitSource_githubAppId_fkey" FOREIGN KEY ("githubAppId") REFERENCES "GithubApp" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
+ CONSTRAINT "GitSource_gitlabAppId_fkey" FOREIGN KEY ("gitlabAppId") REFERENCES "GitlabApp" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+INSERT INTO "new_GitSource" ("apiUrl", "createdAt", "customPort", "githubAppId", "gitlabAppId", "htmlUrl", "id", "name", "organization", "type", "updatedAt") SELECT "apiUrl", "createdAt", "customPort", "githubAppId", "gitlabAppId", "htmlUrl", "id", "name", "organization", "type", "updatedAt" FROM "GitSource";
+DROP TABLE "GitSource";
+ALTER TABLE "new_GitSource" RENAME TO "GitSource";
+CREATE UNIQUE INDEX "GitSource_githubAppId_key" ON "GitSource"("githubAppId");
+CREATE UNIQUE INDEX "GitSource_gitlabAppId_key" ON "GitSource"("gitlabAppId");
+CREATE TABLE "new_ApplicationSettings" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "applicationId" TEXT NOT NULL,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "debug" BOOLEAN NOT NULL DEFAULT false,
+ "previews" BOOLEAN NOT NULL DEFAULT false,
+ "autodeploy" BOOLEAN NOT NULL DEFAULT true,
+ "isBot" BOOLEAN NOT NULL DEFAULT false,
+ "isPublicRepository" BOOLEAN NOT NULL DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "ApplicationSettings_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_ApplicationSettings" ("applicationId", "autodeploy", "createdAt", "debug", "dualCerts", "id", "isBot", "previews", "updatedAt") SELECT "applicationId", "autodeploy", "createdAt", "debug", "dualCerts", "id", "isBot", "previews", "updatedAt" FROM "ApplicationSettings";
+DROP TABLE "ApplicationSettings";
+ALTER TABLE "new_ApplicationSettings" RENAME TO "ApplicationSettings";
+CREATE UNIQUE INDEX "ApplicationSettings_applicationId_key" ON "ApplicationSettings"("applicationId");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220823070532_service_searxng/migration.sql b/apps/server/prisma/migrations/20220823070532_service_searxng/migration.sql
new file mode 100644
index 000000000..81ecc81c8
--- /dev/null
+++ b/apps/server/prisma/migrations/20220823070532_service_searxng/migration.sql
@@ -0,0 +1,13 @@
+-- CreateTable
+CREATE TABLE "Searxng" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "secretKey" TEXT NOT NULL,
+ "redisPassword" TEXT NOT NULL,
+ "serviceId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Searxng_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Searxng_serviceId_key" ON "Searxng"("serviceId");
diff --git a/apps/server/prisma/migrations/20220825064811_concurrent_build_settings/migration.sql b/apps/server/prisma/migrations/20220825064811_concurrent_build_settings/migration.sql
new file mode 100644
index 000000000..1535c2bf7
--- /dev/null
+++ b/apps/server/prisma/migrations/20220825064811_concurrent_build_settings/migration.sql
@@ -0,0 +1,29 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Setting" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "fqdn" TEXT,
+ "isRegistrationEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "minPort" INTEGER NOT NULL DEFAULT 9000,
+ "maxPort" INTEGER NOT NULL DEFAULT 9100,
+ "proxyPassword" TEXT NOT NULL,
+ "proxyUser" TEXT NOT NULL,
+ "proxyHash" TEXT,
+ "isAutoUpdateEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "isDNSCheckEnabled" BOOLEAN NOT NULL DEFAULT true,
+ "DNSServers" TEXT,
+ "isTraefikUsed" BOOLEAN NOT NULL DEFAULT true,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "ipv4" TEXT,
+ "ipv6" TEXT,
+ "arch" TEXT,
+ "concurrentBuilds" INTEGER NOT NULL DEFAULT 1
+);
+INSERT INTO "new_Setting" ("DNSServers", "arch", "createdAt", "dualCerts", "fqdn", "id", "ipv4", "ipv6", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "isTraefikUsed", "maxPort", "minPort", "proxyHash", "proxyPassword", "proxyUser", "updatedAt") SELECT "DNSServers", "arch", "createdAt", "dualCerts", "fqdn", "id", "ipv4", "ipv6", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "isTraefikUsed", "maxPort", "minPort", "proxyHash", "proxyPassword", "proxyUser", "updatedAt" FROM "Setting";
+DROP TABLE "Setting";
+ALTER TABLE "new_Setting" RENAME TO "Setting";
+CREATE UNIQUE INDEX "Setting_fqdn_key" ON "Setting"("fqdn");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220825072007_build_queue_improvements/migration.sql b/apps/server/prisma/migrations/20220825072007_build_queue_improvements/migration.sql
new file mode 100644
index 000000000..78c51fc15
--- /dev/null
+++ b/apps/server/prisma/migrations/20220825072007_build_queue_improvements/migration.sql
@@ -0,0 +1,24 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Build" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "type" TEXT NOT NULL,
+ "applicationId" TEXT,
+ "destinationDockerId" TEXT,
+ "gitSourceId" TEXT,
+ "githubAppId" TEXT,
+ "gitlabAppId" TEXT,
+ "commit" TEXT,
+ "pullmergeRequestId" TEXT,
+ "forceRebuild" BOOLEAN NOT NULL DEFAULT false,
+ "sourceBranch" TEXT,
+ "branch" TEXT,
+ "status" TEXT DEFAULT 'queued',
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+INSERT INTO "new_Build" ("applicationId", "branch", "commit", "createdAt", "destinationDockerId", "gitSourceId", "githubAppId", "gitlabAppId", "id", "status", "type", "updatedAt") SELECT "applicationId", "branch", "commit", "createdAt", "destinationDockerId", "gitSourceId", "githubAppId", "gitlabAppId", "id", "status", "type", "updatedAt" FROM "Build";
+DROP TABLE "Build";
+ALTER TABLE "new_Build" RENAME TO "Build";
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220831095714_service_weblate/migration.sql b/apps/server/prisma/migrations/20220831095714_service_weblate/migration.sql
new file mode 100644
index 000000000..c985b4ae2
--- /dev/null
+++ b/apps/server/prisma/migrations/20220831095714_service_weblate/migration.sql
@@ -0,0 +1,18 @@
+-- CreateTable
+CREATE TABLE "Weblate" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "adminPassword" TEXT NOT NULL,
+ "postgresqlHost" TEXT NOT NULL,
+ "postgresqlPort" INTEGER NOT NULL,
+ "postgresqlUser" TEXT NOT NULL,
+ "postgresqlPassword" TEXT NOT NULL,
+ "postgresqlDatabase" TEXT NOT NULL,
+ "postgresqlPublicPort" INTEGER,
+ "serviceId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Weblate_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Weblate_serviceId_key" ON "Weblate"("serviceId");
diff --git a/apps/server/prisma/migrations/20220902115640_service_taiga/migration.sql b/apps/server/prisma/migrations/20220902115640_service_taiga/migration.sql
new file mode 100644
index 000000000..3035dd8ef
--- /dev/null
+++ b/apps/server/prisma/migrations/20220902115640_service_taiga/migration.sql
@@ -0,0 +1,23 @@
+-- CreateTable
+CREATE TABLE "Taiga" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "secretKey" TEXT NOT NULL,
+ "erlangSecret" TEXT NOT NULL,
+ "djangoAdminPassword" TEXT NOT NULL,
+ "djangoAdminUser" TEXT NOT NULL,
+ "rabbitMQUser" TEXT NOT NULL,
+ "rabbitMQPassword" TEXT NOT NULL,
+ "postgresqlHost" TEXT NOT NULL,
+ "postgresqlPort" INTEGER NOT NULL,
+ "postgresqlUser" TEXT NOT NULL,
+ "postgresqlPassword" TEXT NOT NULL,
+ "postgresqlDatabase" TEXT NOT NULL,
+ "postgresqlPublicPort" INTEGER,
+ "serviceId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Taiga_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Taiga_serviceId_key" ON "Taiga"("serviceId");
diff --git a/apps/server/prisma/migrations/20220905062318_database_branching/migration.sql b/apps/server/prisma/migrations/20220905062318_database_branching/migration.sql
new file mode 100644
index 000000000..d828a4c66
--- /dev/null
+++ b/apps/server/prisma/migrations/20220905062318_database_branching/migration.sql
@@ -0,0 +1,22 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_ApplicationSettings" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "applicationId" TEXT NOT NULL,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "debug" BOOLEAN NOT NULL DEFAULT false,
+ "previews" BOOLEAN NOT NULL DEFAULT false,
+ "autodeploy" BOOLEAN NOT NULL DEFAULT true,
+ "isBot" BOOLEAN NOT NULL DEFAULT false,
+ "isPublicRepository" BOOLEAN NOT NULL DEFAULT false,
+ "isDBBranching" BOOLEAN NOT NULL DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "ApplicationSettings_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_ApplicationSettings" ("applicationId", "autodeploy", "createdAt", "debug", "dualCerts", "id", "isBot", "isPublicRepository", "previews", "updatedAt") SELECT "applicationId", "autodeploy", "createdAt", "debug", "dualCerts", "id", "isBot", "isPublicRepository", "previews", "updatedAt" FROM "ApplicationSettings";
+DROP TABLE "ApplicationSettings";
+ALTER TABLE "new_ApplicationSettings" RENAME TO "ApplicationSettings";
+CREATE UNIQUE INDEX "ApplicationSettings_applicationId_key" ON "ApplicationSettings"("applicationId");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220905113241_prisma_migration/migration.sql b/apps/server/prisma/migrations/20220905113241_prisma_migration/migration.sql
new file mode 100644
index 000000000..324bcfff0
--- /dev/null
+++ b/apps/server/prisma/migrations/20220905113241_prisma_migration/migration.sql
@@ -0,0 +1,20 @@
+/*
+ Warnings:
+
+ - You are about to alter the column `time` on the `BuildLog` table. The data in that column could be lost. The data in that column will be cast from `Int` to `BigInt`.
+
+*/
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_BuildLog" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "applicationId" TEXT,
+ "buildId" TEXT NOT NULL,
+ "line" TEXT NOT NULL,
+ "time" BIGINT NOT NULL
+);
+INSERT INTO "new_BuildLog" ("applicationId", "buildId", "id", "line", "time") SELECT "applicationId", "buildId", "id", "line", "time" FROM "BuildLog";
+DROP TABLE "BuildLog";
+ALTER TABLE "new_BuildLog" RENAME TO "BuildLog";
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220905115321_application_connected_database/migration.sql b/apps/server/prisma/migrations/20220905115321_application_connected_database/migration.sql
new file mode 100644
index 000000000..576c23bdf
--- /dev/null
+++ b/apps/server/prisma/migrations/20220905115321_application_connected_database/migration.sql
@@ -0,0 +1,20 @@
+-- CreateTable
+CREATE TABLE "ApplicationConnectedDatabase" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "applicationId" TEXT NOT NULL,
+ "databaseId" TEXT,
+ "hostedDatabaseType" TEXT,
+ "hostedDatabaseHost" TEXT,
+ "hostedDatabasePort" INTEGER,
+ "hostedDatabaseName" TEXT,
+ "hostedDatabaseUser" TEXT,
+ "hostedDatabasePassword" TEXT,
+ "hostedDatabaseDBName" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "ApplicationConnectedDatabase_databaseId_fkey" FOREIGN KEY ("databaseId") REFERENCES "Database" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
+ CONSTRAINT "ApplicationConnectedDatabase_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "ApplicationConnectedDatabase_applicationId_key" ON "ApplicationConnectedDatabase"("applicationId");
diff --git a/apps/server/prisma/migrations/20220906120112_enable_api_debug_logging/migration.sql b/apps/server/prisma/migrations/20220906120112_enable_api_debug_logging/migration.sql
new file mode 100644
index 000000000..05fb3e285
--- /dev/null
+++ b/apps/server/prisma/migrations/20220906120112_enable_api_debug_logging/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Setting" ADD COLUMN "isAPIDebuggingEnabled" BOOLEAN DEFAULT false;
diff --git a/apps/server/prisma/migrations/20220907092244_database_secrets/migration.sql b/apps/server/prisma/migrations/20220907092244_database_secrets/migration.sql
new file mode 100644
index 000000000..53ff2d19e
--- /dev/null
+++ b/apps/server/prisma/migrations/20220907092244_database_secrets/migration.sql
@@ -0,0 +1,13 @@
+-- CreateTable
+CREATE TABLE "DatabaseSecret" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "value" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "databaseId" TEXT NOT NULL,
+ CONSTRAINT "DatabaseSecret_databaseId_fkey" FOREIGN KEY ("databaseId") REFERENCES "Database" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "DatabaseSecret_name_databaseId_key" ON "DatabaseSecret"("name", "databaseId");
diff --git a/apps/server/prisma/migrations/20220913092100_preview_applications/migration.sql b/apps/server/prisma/migrations/20220913092100_preview_applications/migration.sql
new file mode 100644
index 000000000..0ec1aafa0
--- /dev/null
+++ b/apps/server/prisma/migrations/20220913092100_preview_applications/migration.sql
@@ -0,0 +1,18 @@
+-- AlterTable
+ALTER TABLE "Build" ADD COLUMN "previewApplicationId" TEXT;
+
+-- CreateTable
+CREATE TABLE "PreviewApplication" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "pullmergeRequestId" TEXT NOT NULL,
+ "sourceBranch" TEXT NOT NULL,
+ "isRandomDomain" BOOLEAN NOT NULL DEFAULT false,
+ "customDomain" TEXT,
+ "applicationId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "PreviewApplication_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "PreviewApplication_applicationId_key" ON "PreviewApplication"("applicationId");
diff --git a/apps/server/prisma/migrations/20220922064605_custom_certificates/migration.sql b/apps/server/prisma/migrations/20220922064605_custom_certificates/migration.sql
new file mode 100644
index 000000000..804913038
--- /dev/null
+++ b/apps/server/prisma/migrations/20220922064605_custom_certificates/migration.sql
@@ -0,0 +1,10 @@
+-- CreateTable
+CREATE TABLE "Certificate" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "key" TEXT NOT NULL,
+ "cert" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "teamId" TEXT,
+ CONSTRAINT "Certificate_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
diff --git a/apps/server/prisma/migrations/20220923122227_custom_ssl_for_applications/migration.sql b/apps/server/prisma/migrations/20220923122227_custom_ssl_for_applications/migration.sql
new file mode 100644
index 000000000..b9261a955
--- /dev/null
+++ b/apps/server/prisma/migrations/20220923122227_custom_ssl_for_applications/migration.sql
@@ -0,0 +1,23 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_ApplicationSettings" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "applicationId" TEXT NOT NULL,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "debug" BOOLEAN NOT NULL DEFAULT false,
+ "previews" BOOLEAN NOT NULL DEFAULT false,
+ "autodeploy" BOOLEAN NOT NULL DEFAULT true,
+ "isBot" BOOLEAN NOT NULL DEFAULT false,
+ "isPublicRepository" BOOLEAN NOT NULL DEFAULT false,
+ "isDBBranching" BOOLEAN NOT NULL DEFAULT false,
+ "isCustomSSL" BOOLEAN NOT NULL DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "ApplicationSettings_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_ApplicationSettings" ("applicationId", "autodeploy", "createdAt", "debug", "dualCerts", "id", "isBot", "isDBBranching", "isPublicRepository", "previews", "updatedAt") SELECT "applicationId", "autodeploy", "createdAt", "debug", "dualCerts", "id", "isBot", "isDBBranching", "isPublicRepository", "previews", "updatedAt" FROM "ApplicationSettings";
+DROP TABLE "ApplicationSettings";
+ALTER TABLE "new_ApplicationSettings" RENAME TO "ApplicationSettings";
+CREATE UNIQUE INDEX "ApplicationSettings_applicationId_key" ON "ApplicationSettings"("applicationId");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20220928083348_system_wide_git_sources/migration.sql b/apps/server/prisma/migrations/20220928083348_system_wide_git_sources/migration.sql
new file mode 100644
index 000000000..a3657504d
--- /dev/null
+++ b/apps/server/prisma/migrations/20220928083348_system_wide_git_sources/migration.sql
@@ -0,0 +1,26 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_GitSource" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "forPublic" BOOLEAN NOT NULL DEFAULT false,
+ "type" TEXT,
+ "apiUrl" TEXT,
+ "htmlUrl" TEXT,
+ "customPort" INTEGER NOT NULL DEFAULT 22,
+ "organization" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "githubAppId" TEXT,
+ "gitlabAppId" TEXT,
+ "isSystemWide" BOOLEAN NOT NULL DEFAULT false,
+ CONSTRAINT "GitSource_gitlabAppId_fkey" FOREIGN KEY ("gitlabAppId") REFERENCES "GitlabApp" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
+ CONSTRAINT "GitSource_githubAppId_fkey" FOREIGN KEY ("githubAppId") REFERENCES "GithubApp" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+INSERT INTO "new_GitSource" ("apiUrl", "createdAt", "customPort", "forPublic", "githubAppId", "gitlabAppId", "htmlUrl", "id", "name", "organization", "type", "updatedAt") SELECT "apiUrl", "createdAt", "customPort", "forPublic", "githubAppId", "gitlabAppId", "htmlUrl", "id", "name", "organization", "type", "updatedAt" FROM "GitSource";
+DROP TABLE "GitSource";
+ALTER TABLE "new_GitSource" RENAME TO "GitSource";
+CREATE UNIQUE INDEX "GitSource_githubAppId_key" ON "GitSource"("githubAppId");
+CREATE UNIQUE INDEX "GitSource_gitlabAppId_key" ON "GitSource"("gitlabAppId");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20221002084246_no_unique_appid_on_previews/migration.sql b/apps/server/prisma/migrations/20221002084246_no_unique_appid_on_previews/migration.sql
new file mode 100644
index 000000000..031f842cb
--- /dev/null
+++ b/apps/server/prisma/migrations/20221002084246_no_unique_appid_on_previews/migration.sql
@@ -0,0 +1,2 @@
+-- DropIndex
+DROP INDEX "PreviewApplication_applicationId_key";
diff --git a/apps/server/prisma/migrations/20221002091630_forked_previews/migration.sql b/apps/server/prisma/migrations/20221002091630_forked_previews/migration.sql
new file mode 100644
index 000000000..2312c011b
--- /dev/null
+++ b/apps/server/prisma/migrations/20221002091630_forked_previews/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Build" ADD COLUMN "sourceRepository" TEXT;
diff --git a/apps/server/prisma/migrations/20221005120323_initial_docker_compose/migration.sql b/apps/server/prisma/migrations/20221005120323_initial_docker_compose/migration.sql
new file mode 100644
index 000000000..bb93e1aaf
--- /dev/null
+++ b/apps/server/prisma/migrations/20221005120323_initial_docker_compose/migration.sql
@@ -0,0 +1,3 @@
+-- AlterTable
+ALTER TABLE "Application" ADD COLUMN "dockerComposeFile" TEXT;
+ALTER TABLE "Application" ADD COLUMN "dockerComposeFileLocation" TEXT;
diff --git a/apps/server/prisma/migrations/20221005132352_docker_compose_configuration/migration.sql b/apps/server/prisma/migrations/20221005132352_docker_compose_configuration/migration.sql
new file mode 100644
index 000000000..e7368dc1a
--- /dev/null
+++ b/apps/server/prisma/migrations/20221005132352_docker_compose_configuration/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Application" ADD COLUMN "dockerComposeConfiguration" TEXT;
diff --git a/apps/server/prisma/migrations/20221017134342_standardized_service_configs/migration.sql b/apps/server/prisma/migrations/20221017134342_standardized_service_configs/migration.sql
new file mode 100644
index 000000000..837017435
--- /dev/null
+++ b/apps/server/prisma/migrations/20221017134342_standardized_service_configs/migration.sql
@@ -0,0 +1,13 @@
+-- CreateTable
+CREATE TABLE "ServiceSetting" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "serviceId" TEXT NOT NULL,
+ "name" TEXT NOT NULL,
+ "value" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "ServiceSetting_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "ServiceSetting_serviceId_name_key" ON "ServiceSetting"("serviceId", "name");
diff --git a/apps/server/prisma/migrations/20221018090939_service_peristent_volumes_predefined/migration.sql b/apps/server/prisma/migrations/20221018090939_service_peristent_volumes_predefined/migration.sql
new file mode 100644
index 000000000..c7b935eb7
--- /dev/null
+++ b/apps/server/prisma/migrations/20221018090939_service_peristent_volumes_predefined/migration.sql
@@ -0,0 +1,19 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_ServicePersistentStorage" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "serviceId" TEXT NOT NULL,
+ "path" TEXT NOT NULL,
+ "volumeName" TEXT,
+ "predefined" BOOLEAN NOT NULL DEFAULT false,
+ "containerId" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "ServicePersistentStorage_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_ServicePersistentStorage" ("createdAt", "id", "path", "serviceId", "updatedAt") SELECT "createdAt", "id", "path", "serviceId", "updatedAt" FROM "ServicePersistentStorage";
+DROP TABLE "ServicePersistentStorage";
+ALTER TABLE "new_ServicePersistentStorage" RENAME TO "ServicePersistentStorage";
+CREATE UNIQUE INDEX "ServicePersistentStorage_serviceId_path_key" ON "ServicePersistentStorage"("serviceId", "path");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20221021112429_serivce_settings_extended/migration.sql b/apps/server/prisma/migrations/20221021112429_serivce_settings_extended/migration.sql
new file mode 100644
index 000000000..b2eddcfd9
--- /dev/null
+++ b/apps/server/prisma/migrations/20221021112429_serivce_settings_extended/migration.sql
@@ -0,0 +1,24 @@
+/*
+ Warnings:
+
+ - Added the required column `variableName` to the `ServiceSetting` table without a default value. This is not possible if the table is not empty.
+
+*/
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_ServiceSetting" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "serviceId" TEXT NOT NULL,
+ "name" TEXT NOT NULL,
+ "value" TEXT NOT NULL,
+ "variableName" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "ServiceSetting_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_ServiceSetting" ("createdAt", "id", "name", "serviceId", "updatedAt", "value") SELECT "createdAt", "id", "name", "serviceId", "updatedAt", "value" FROM "ServiceSetting";
+DROP TABLE "ServiceSetting";
+ALTER TABLE "new_ServiceSetting" RENAME TO "ServiceSetting";
+CREATE UNIQUE INDEX "ServiceSetting_serviceId_name_key" ON "ServiceSetting"("serviceId", "name");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20221021185630_service_template_version/migration.sql b/apps/server/prisma/migrations/20221021185630_service_template_version/migration.sql
new file mode 100644
index 000000000..f716a2340
--- /dev/null
+++ b/apps/server/prisma/migrations/20221021185630_service_template_version/migration.sql
@@ -0,0 +1,21 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Service" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "fqdn" TEXT,
+ "exposePort" INTEGER,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "type" TEXT,
+ "version" TEXT,
+ "templateVersion" TEXT NOT NULL DEFAULT '0.0.0',
+ "destinationDockerId" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Service_destinationDockerId_fkey" FOREIGN KEY ("destinationDockerId") REFERENCES "DestinationDocker" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+INSERT INTO "new_Service" ("createdAt", "destinationDockerId", "dualCerts", "exposePort", "fqdn", "id", "name", "type", "updatedAt", "version") SELECT "createdAt", "destinationDockerId", "dualCerts", "exposePort", "fqdn", "id", "name", "type", "updatedAt", "version" FROM "Service";
+DROP TABLE "Service";
+ALTER TABLE "new_Service" RENAME TO "Service";
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20221026115123_service_persistent_unique/migration.sql b/apps/server/prisma/migrations/20221026115123_service_persistent_unique/migration.sql
new file mode 100644
index 000000000..dae80a76a
--- /dev/null
+++ b/apps/server/prisma/migrations/20221026115123_service_persistent_unique/migration.sql
@@ -0,0 +1,11 @@
+/*
+ Warnings:
+
+ - A unique constraint covering the columns `[serviceId,containerId,path]` on the table `ServicePersistentStorage` will be added. If there are existing duplicate values, this will fail.
+
+*/
+-- DropIndex
+DROP INDEX "ServicePersistentStorage_serviceId_path_key";
+
+-- CreateIndex
+CREATE UNIQUE INDEX "ServicePersistentStorage_serviceId_containerId_path_key" ON "ServicePersistentStorage"("serviceId", "containerId", "path");
diff --git a/apps/server/prisma/migrations/20221028074301_wordpress_optional_fields/migration.sql b/apps/server/prisma/migrations/20221028074301_wordpress_optional_fields/migration.sql
new file mode 100644
index 000000000..217039d97
--- /dev/null
+++ b/apps/server/prisma/migrations/20221028074301_wordpress_optional_fields/migration.sql
@@ -0,0 +1,32 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Wordpress" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "extraConfig" TEXT,
+ "tablePrefix" TEXT,
+ "ownMysql" BOOLEAN NOT NULL DEFAULT false,
+ "mysqlHost" TEXT,
+ "mysqlPort" INTEGER,
+ "mysqlUser" TEXT,
+ "mysqlPassword" TEXT,
+ "mysqlRootUser" TEXT,
+ "mysqlRootUserPassword" TEXT,
+ "mysqlDatabase" TEXT,
+ "mysqlPublicPort" INTEGER,
+ "ftpEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "ftpUser" TEXT,
+ "ftpPassword" TEXT,
+ "ftpPublicPort" INTEGER,
+ "ftpHostKey" TEXT,
+ "ftpHostKeyPrivate" TEXT,
+ "serviceId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Wordpress_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_Wordpress" ("createdAt", "extraConfig", "ftpEnabled", "ftpHostKey", "ftpHostKeyPrivate", "ftpPassword", "ftpPublicPort", "ftpUser", "id", "mysqlDatabase", "mysqlHost", "mysqlPassword", "mysqlPort", "mysqlPublicPort", "mysqlRootUser", "mysqlRootUserPassword", "mysqlUser", "ownMysql", "serviceId", "tablePrefix", "updatedAt") SELECT "createdAt", "extraConfig", "ftpEnabled", "ftpHostKey", "ftpHostKeyPrivate", "ftpPassword", "ftpPublicPort", "ftpUser", "id", "mysqlDatabase", "mysqlHost", "mysqlPassword", "mysqlPort", "mysqlPublicPort", "mysqlRootUser", "mysqlRootUserPassword", "mysqlUser", "ownMysql", "serviceId", "tablePrefix", "updatedAt" FROM "Wordpress";
+DROP TABLE "Wordpress";
+ALTER TABLE "new_Wordpress" RENAME TO "Wordpress";
+CREATE UNIQUE INDEX "Wordpress_serviceId_key" ON "Wordpress"("serviceId");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20221104092223_default_redirect_proxy/migration.sql b/apps/server/prisma/migrations/20221104092223_default_redirect_proxy/migration.sql
new file mode 100644
index 000000000..8584fe25c
--- /dev/null
+++ b/apps/server/prisma/migrations/20221104092223_default_redirect_proxy/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Setting" ADD COLUMN "proxyDefaultRedirect" TEXT;
diff --git a/apps/server/prisma/migrations/20221114093217_application_storage_path_migration/migration.sql b/apps/server/prisma/migrations/20221114093217_application_storage_path_migration/migration.sql
new file mode 100644
index 000000000..6913c8b00
--- /dev/null
+++ b/apps/server/prisma/migrations/20221114093217_application_storage_path_migration/migration.sql
@@ -0,0 +1,45 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Setting" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "fqdn" TEXT,
+ "isAPIDebuggingEnabled" BOOLEAN DEFAULT false,
+ "isRegistrationEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "minPort" INTEGER NOT NULL DEFAULT 9000,
+ "maxPort" INTEGER NOT NULL DEFAULT 9100,
+ "proxyPassword" TEXT NOT NULL,
+ "proxyUser" TEXT NOT NULL,
+ "proxyHash" TEXT,
+ "proxyDefaultRedirect" TEXT,
+ "isAutoUpdateEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "isDNSCheckEnabled" BOOLEAN NOT NULL DEFAULT true,
+ "DNSServers" TEXT,
+ "isTraefikUsed" BOOLEAN NOT NULL DEFAULT true,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "ipv4" TEXT,
+ "ipv6" TEXT,
+ "arch" TEXT,
+ "concurrentBuilds" INTEGER NOT NULL DEFAULT 1,
+ "applicationStoragePathMigrationFinished" BOOLEAN NOT NULL DEFAULT false
+);
+INSERT INTO "new_Setting" ("DNSServers", "arch", "concurrentBuilds", "createdAt", "dualCerts", "fqdn", "id", "ipv4", "ipv6", "isAPIDebuggingEnabled", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "isTraefikUsed", "maxPort", "minPort", "proxyDefaultRedirect", "proxyHash", "proxyPassword", "proxyUser", "updatedAt") SELECT "DNSServers", "arch", "concurrentBuilds", "createdAt", "dualCerts", "fqdn", "id", "ipv4", "ipv6", "isAPIDebuggingEnabled", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "isTraefikUsed", "maxPort", "minPort", "proxyDefaultRedirect", "proxyHash", "proxyPassword", "proxyUser", "updatedAt" FROM "Setting";
+DROP TABLE "Setting";
+ALTER TABLE "new_Setting" RENAME TO "Setting";
+CREATE UNIQUE INDEX "Setting_fqdn_key" ON "Setting"("fqdn");
+CREATE TABLE "new_ApplicationPersistentStorage" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "applicationId" TEXT NOT NULL,
+ "path" TEXT NOT NULL,
+ "oldPath" BOOLEAN NOT NULL DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "ApplicationPersistentStorage_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_ApplicationPersistentStorage" ("applicationId", "createdAt", "id", "path", "updatedAt") SELECT "applicationId", "createdAt", "id", "path", "updatedAt" FROM "ApplicationPersistentStorage";
+DROP TABLE "ApplicationPersistentStorage";
+ALTER TABLE "new_ApplicationPersistentStorage" RENAME TO "ApplicationPersistentStorage";
+CREATE UNIQUE INDEX "ApplicationPersistentStorage_applicationId_path_key" ON "ApplicationPersistentStorage"("applicationId", "path");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20221123122143_remote_haproxy_from_db/migration.sql b/apps/server/prisma/migrations/20221123122143_remote_haproxy_from_db/migration.sql
new file mode 100644
index 000000000..1acf261a5
--- /dev/null
+++ b/apps/server/prisma/migrations/20221123122143_remote_haproxy_from_db/migration.sql
@@ -0,0 +1,37 @@
+/*
+ Warnings:
+
+ - You are about to drop the column `proxyHash` on the `Setting` table. All the data in the column will be lost.
+ - You are about to drop the column `proxyPassword` on the `Setting` table. All the data in the column will be lost.
+ - You are about to drop the column `proxyUser` on the `Setting` table. All the data in the column will be lost.
+
+*/
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Setting" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "fqdn" TEXT,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "minPort" INTEGER NOT NULL DEFAULT 9000,
+ "maxPort" INTEGER NOT NULL DEFAULT 9100,
+ "DNSServers" TEXT,
+ "ipv4" TEXT,
+ "ipv6" TEXT,
+ "arch" TEXT,
+ "concurrentBuilds" INTEGER NOT NULL DEFAULT 1,
+ "applicationStoragePathMigrationFinished" BOOLEAN NOT NULL DEFAULT false,
+ "proxyDefaultRedirect" TEXT,
+ "isAPIDebuggingEnabled" BOOLEAN DEFAULT false,
+ "isRegistrationEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "isAutoUpdateEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "isDNSCheckEnabled" BOOLEAN NOT NULL DEFAULT true,
+ "isTraefikUsed" BOOLEAN NOT NULL DEFAULT true,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+INSERT INTO "new_Setting" ("DNSServers", "applicationStoragePathMigrationFinished", "arch", "concurrentBuilds", "createdAt", "dualCerts", "fqdn", "id", "ipv4", "ipv6", "isAPIDebuggingEnabled", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "isTraefikUsed", "maxPort", "minPort", "proxyDefaultRedirect", "updatedAt") SELECT "DNSServers", "applicationStoragePathMigrationFinished", "arch", "concurrentBuilds", "createdAt", "dualCerts", "fqdn", "id", "ipv4", "ipv6", "isAPIDebuggingEnabled", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "isTraefikUsed", "maxPort", "minPort", "proxyDefaultRedirect", "updatedAt" FROM "Setting";
+DROP TABLE "Setting";
+ALTER TABLE "new_Setting" RENAME TO "Setting";
+CREATE UNIQUE INDEX "Setting_fqdn_key" ON "Setting"("fqdn");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20221123133429_docker_registries/migration.sql b/apps/server/prisma/migrations/20221123133429_docker_registries/migration.sql
new file mode 100644
index 000000000..abebc5514
--- /dev/null
+++ b/apps/server/prisma/migrations/20221123133429_docker_registries/migration.sql
@@ -0,0 +1,59 @@
+-- CreateTable
+CREATE TABLE "DockerRegistry" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "url" TEXT NOT NULL,
+ "username" TEXT,
+ "password" TEXT,
+ "isSystemWide" BOOLEAN NOT NULL DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "teamId" TEXT,
+ CONSTRAINT "DockerRegistry_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Application" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "fqdn" TEXT,
+ "repository" TEXT,
+ "configHash" TEXT,
+ "branch" TEXT,
+ "buildPack" TEXT,
+ "projectId" INTEGER,
+ "port" INTEGER,
+ "exposePort" INTEGER,
+ "installCommand" TEXT,
+ "buildCommand" TEXT,
+ "startCommand" TEXT,
+ "baseDirectory" TEXT,
+ "publishDirectory" TEXT,
+ "deploymentType" TEXT,
+ "phpModules" TEXT,
+ "pythonWSGI" TEXT,
+ "pythonModule" TEXT,
+ "pythonVariable" TEXT,
+ "dockerFileLocation" TEXT,
+ "denoMainFile" TEXT,
+ "denoOptions" TEXT,
+ "dockerComposeFile" TEXT,
+ "dockerComposeFileLocation" TEXT,
+ "dockerComposeConfiguration" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "destinationDockerId" TEXT,
+ "gitSourceId" TEXT,
+ "baseImage" TEXT,
+ "baseBuildImage" TEXT,
+ "dockerRegistryId" TEXT NOT NULL DEFAULT '0',
+ CONSTRAINT "Application_gitSourceId_fkey" FOREIGN KEY ("gitSourceId") REFERENCES "GitSource" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
+ CONSTRAINT "Application_destinationDockerId_fkey" FOREIGN KEY ("destinationDockerId") REFERENCES "DestinationDocker" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
+ CONSTRAINT "Application_dockerRegistryId_fkey" FOREIGN KEY ("dockerRegistryId") REFERENCES "DockerRegistry" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_Application" ("baseBuildImage", "baseDirectory", "baseImage", "branch", "buildCommand", "buildPack", "configHash", "createdAt", "denoMainFile", "denoOptions", "deploymentType", "destinationDockerId", "dockerComposeConfiguration", "dockerComposeFile", "dockerComposeFileLocation", "dockerFileLocation", "exposePort", "fqdn", "gitSourceId", "id", "installCommand", "name", "phpModules", "port", "projectId", "publishDirectory", "pythonModule", "pythonVariable", "pythonWSGI", "repository", "startCommand", "updatedAt") SELECT "baseBuildImage", "baseDirectory", "baseImage", "branch", "buildCommand", "buildPack", "configHash", "createdAt", "denoMainFile", "denoOptions", "deploymentType", "destinationDockerId", "dockerComposeConfiguration", "dockerComposeFile", "dockerComposeFileLocation", "dockerFileLocation", "exposePort", "fqdn", "gitSourceId", "id", "installCommand", "name", "phpModules", "port", "projectId", "publishDirectory", "pythonModule", "pythonVariable", "pythonWSGI", "repository", "startCommand", "updatedAt" FROM "Application";
+DROP TABLE "Application";
+ALTER TABLE "new_Application" RENAME TO "Application";
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20221128104158_do_not_track/migration.sql b/apps/server/prisma/migrations/20221128104158_do_not_track/migration.sql
new file mode 100644
index 000000000..9cf26d8a8
--- /dev/null
+++ b/apps/server/prisma/migrations/20221128104158_do_not_track/migration.sql
@@ -0,0 +1,30 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Setting" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "fqdn" TEXT,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "minPort" INTEGER NOT NULL DEFAULT 9000,
+ "maxPort" INTEGER NOT NULL DEFAULT 9100,
+ "DNSServers" TEXT,
+ "ipv4" TEXT,
+ "ipv6" TEXT,
+ "arch" TEXT,
+ "concurrentBuilds" INTEGER NOT NULL DEFAULT 1,
+ "applicationStoragePathMigrationFinished" BOOLEAN NOT NULL DEFAULT false,
+ "proxyDefaultRedirect" TEXT,
+ "doNotTrack" BOOLEAN NOT NULL DEFAULT false,
+ "isAPIDebuggingEnabled" BOOLEAN DEFAULT false,
+ "isRegistrationEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "isAutoUpdateEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "isDNSCheckEnabled" BOOLEAN NOT NULL DEFAULT true,
+ "isTraefikUsed" BOOLEAN NOT NULL DEFAULT true,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+INSERT INTO "new_Setting" ("DNSServers", "applicationStoragePathMigrationFinished", "arch", "concurrentBuilds", "createdAt", "dualCerts", "fqdn", "id", "ipv4", "ipv6", "isAPIDebuggingEnabled", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "isTraefikUsed", "maxPort", "minPort", "proxyDefaultRedirect", "updatedAt") SELECT "DNSServers", "applicationStoragePathMigrationFinished", "arch", "concurrentBuilds", "createdAt", "dualCerts", "fqdn", "id", "ipv4", "ipv6", "isAPIDebuggingEnabled", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "isTraefikUsed", "maxPort", "minPort", "proxyDefaultRedirect", "updatedAt" FROM "Setting";
+DROP TABLE "Setting";
+ALTER TABLE "new_Setting" RENAME TO "Setting";
+CREATE UNIQUE INDEX "Setting_fqdn_key" ON "Setting"("fqdn");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20221128104718_fix_defaults/migration.sql b/apps/server/prisma/migrations/20221128104718_fix_defaults/migration.sql
new file mode 100644
index 000000000..c1152cdc3
--- /dev/null
+++ b/apps/server/prisma/migrations/20221128104718_fix_defaults/migration.sql
@@ -0,0 +1,60 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Setting" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "fqdn" TEXT,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "minPort" INTEGER NOT NULL DEFAULT 9000,
+ "maxPort" INTEGER NOT NULL DEFAULT 9100,
+ "DNSServers" TEXT,
+ "ipv4" TEXT,
+ "ipv6" TEXT,
+ "arch" TEXT,
+ "concurrentBuilds" INTEGER NOT NULL DEFAULT 1,
+ "applicationStoragePathMigrationFinished" BOOLEAN NOT NULL DEFAULT false,
+ "proxyDefaultRedirect" TEXT,
+ "doNotTrack" BOOLEAN NOT NULL DEFAULT false,
+ "isAPIDebuggingEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "isRegistrationEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "isAutoUpdateEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "isDNSCheckEnabled" BOOLEAN NOT NULL DEFAULT true,
+ "isTraefikUsed" BOOLEAN NOT NULL DEFAULT true,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+INSERT INTO "new_Setting" ("DNSServers", "applicationStoragePathMigrationFinished", "arch", "concurrentBuilds", "createdAt", "doNotTrack", "dualCerts", "fqdn", "id", "ipv4", "ipv6", "isAPIDebuggingEnabled", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "isTraefikUsed", "maxPort", "minPort", "proxyDefaultRedirect", "updatedAt") SELECT "DNSServers", "applicationStoragePathMigrationFinished", "arch", "concurrentBuilds", "createdAt", "doNotTrack", "dualCerts", "fqdn", "id", "ipv4", "ipv6", coalesce("isAPIDebuggingEnabled", false) AS "isAPIDebuggingEnabled", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "isTraefikUsed", "maxPort", "minPort", "proxyDefaultRedirect", "updatedAt" FROM "Setting";
+DROP TABLE "Setting";
+ALTER TABLE "new_Setting" RENAME TO "Setting";
+CREATE UNIQUE INDEX "Setting_fqdn_key" ON "Setting"("fqdn");
+CREATE TABLE "new_GlitchTip" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "postgresqlUser" TEXT NOT NULL,
+ "postgresqlPassword" TEXT NOT NULL,
+ "postgresqlDatabase" TEXT NOT NULL,
+ "postgresqlPublicPort" INTEGER,
+ "secretKeyBase" TEXT,
+ "defaultEmail" TEXT NOT NULL,
+ "defaultUsername" TEXT NOT NULL,
+ "defaultPassword" TEXT NOT NULL,
+ "defaultEmailFrom" TEXT NOT NULL DEFAULT 'glitchtip@domain.tdl',
+ "emailSmtpHost" TEXT DEFAULT 'domain.tdl',
+ "emailSmtpPort" INTEGER DEFAULT 25,
+ "emailSmtpUser" TEXT,
+ "emailSmtpPassword" TEXT,
+ "emailSmtpUseTls" BOOLEAN NOT NULL DEFAULT false,
+ "emailSmtpUseSsl" BOOLEAN NOT NULL DEFAULT false,
+ "emailBackend" TEXT,
+ "mailgunApiKey" TEXT,
+ "sendgridApiKey" TEXT,
+ "enableOpenUserRegistration" BOOLEAN NOT NULL DEFAULT true,
+ "serviceId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "GlitchTip_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_GlitchTip" ("createdAt", "defaultEmail", "defaultEmailFrom", "defaultPassword", "defaultUsername", "emailBackend", "emailSmtpHost", "emailSmtpPassword", "emailSmtpPort", "emailSmtpUseSsl", "emailSmtpUseTls", "emailSmtpUser", "enableOpenUserRegistration", "id", "mailgunApiKey", "postgresqlDatabase", "postgresqlPassword", "postgresqlPublicPort", "postgresqlUser", "secretKeyBase", "sendgridApiKey", "serviceId", "updatedAt") SELECT "createdAt", "defaultEmail", "defaultEmailFrom", "defaultPassword", "defaultUsername", "emailBackend", "emailSmtpHost", "emailSmtpPassword", "emailSmtpPort", coalesce("emailSmtpUseSsl", false) AS "emailSmtpUseSsl", coalesce("emailSmtpUseTls", false) AS "emailSmtpUseTls", "emailSmtpUser", "enableOpenUserRegistration", "id", "mailgunApiKey", "postgresqlDatabase", "postgresqlPassword", "postgresqlPublicPort", "postgresqlUser", "secretKeyBase", "sendgridApiKey", "serviceId", "updatedAt" FROM "GlitchTip";
+DROP TABLE "GlitchTip";
+ALTER TABLE "new_GlitchTip" RENAME TO "GlitchTip";
+CREATE UNIQUE INDEX "GlitchTip_serviceId_key" ON "GlitchTip"("serviceId");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20221128105615_custom_sentry/migration.sql b/apps/server/prisma/migrations/20221128105615_custom_sentry/migration.sql
new file mode 100644
index 000000000..00857eb0d
--- /dev/null
+++ b/apps/server/prisma/migrations/20221128105615_custom_sentry/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Setting" ADD COLUMN "sentryDSN" TEXT;
diff --git a/apps/server/prisma/migrations/20221129081832_fix_defaults/migration.sql b/apps/server/prisma/migrations/20221129081832_fix_defaults/migration.sql
new file mode 100644
index 000000000..96f6de3fb
--- /dev/null
+++ b/apps/server/prisma/migrations/20221129081832_fix_defaults/migration.sql
@@ -0,0 +1,31 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Setting" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "fqdn" TEXT,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "minPort" INTEGER NOT NULL DEFAULT 9000,
+ "maxPort" INTEGER NOT NULL DEFAULT 9100,
+ "DNSServers" TEXT NOT NULL DEFAULT '1.1.1.1,8.8.8.8',
+ "ipv4" TEXT,
+ "ipv6" TEXT,
+ "arch" TEXT,
+ "concurrentBuilds" INTEGER NOT NULL DEFAULT 1,
+ "applicationStoragePathMigrationFinished" BOOLEAN NOT NULL DEFAULT false,
+ "proxyDefaultRedirect" TEXT,
+ "doNotTrack" BOOLEAN NOT NULL DEFAULT false,
+ "sentryDSN" TEXT,
+ "isAPIDebuggingEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "isRegistrationEnabled" BOOLEAN NOT NULL DEFAULT true,
+ "isAutoUpdateEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "isDNSCheckEnabled" BOOLEAN NOT NULL DEFAULT true,
+ "isTraefikUsed" BOOLEAN NOT NULL DEFAULT true,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+INSERT INTO "new_Setting" ("DNSServers", "applicationStoragePathMigrationFinished", "arch", "concurrentBuilds", "createdAt", "doNotTrack", "dualCerts", "fqdn", "id", "ipv4", "ipv6", "isAPIDebuggingEnabled", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "isTraefikUsed", "maxPort", "minPort", "proxyDefaultRedirect", "sentryDSN", "updatedAt") SELECT coalesce("DNSServers", '1.1.1.1,8.8.8.8') AS "DNSServers", "applicationStoragePathMigrationFinished", "arch", "concurrentBuilds", "createdAt", "doNotTrack", "dualCerts", "fqdn", "id", "ipv4", "ipv6", "isAPIDebuggingEnabled", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "isTraefikUsed", "maxPort", "minPort", "proxyDefaultRedirect", "sentryDSN", "updatedAt" FROM "Setting";
+DROP TABLE "Setting";
+ALTER TABLE "new_Setting" RENAME TO "Setting";
+CREATE UNIQUE INDEX "Setting_fqdn_key" ON "Setting"("fqdn");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20221129121702_preview_separator/migration.sql b/apps/server/prisma/migrations/20221129121702_preview_separator/migration.sql
new file mode 100644
index 000000000..e0d64cdc8
--- /dev/null
+++ b/apps/server/prisma/migrations/20221129121702_preview_separator/migration.sql
@@ -0,0 +1,33 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Setting" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "fqdn" TEXT,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "minPort" INTEGER NOT NULL DEFAULT 9000,
+ "maxPort" INTEGER NOT NULL DEFAULT 9100,
+ "DNSServers" TEXT NOT NULL DEFAULT '1.1.1.1,8.8.8.8',
+ "ipv4" TEXT,
+ "ipv6" TEXT,
+ "arch" TEXT,
+ "concurrentBuilds" INTEGER NOT NULL DEFAULT 1,
+ "applicationStoragePathMigrationFinished" BOOLEAN NOT NULL DEFAULT false,
+ "numberOfDockerImagesKeptLocally" INTEGER NOT NULL DEFAULT 3,
+ "proxyDefaultRedirect" TEXT,
+ "doNotTrack" BOOLEAN NOT NULL DEFAULT false,
+ "sentryDSN" TEXT,
+ "previewSeparator" TEXT NOT NULL DEFAULT '.',
+ "isAPIDebuggingEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "isRegistrationEnabled" BOOLEAN NOT NULL DEFAULT true,
+ "isAutoUpdateEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "isDNSCheckEnabled" BOOLEAN NOT NULL DEFAULT true,
+ "isTraefikUsed" BOOLEAN NOT NULL DEFAULT true,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+INSERT INTO "new_Setting" ("DNSServers", "applicationStoragePathMigrationFinished", "arch", "concurrentBuilds", "createdAt", "doNotTrack", "dualCerts", "fqdn", "id", "ipv4", "ipv6", "isAPIDebuggingEnabled", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "isTraefikUsed", "maxPort", "minPort", "numberOfDockerImagesKeptLocally", "proxyDefaultRedirect", "sentryDSN", "updatedAt") SELECT "DNSServers", "applicationStoragePathMigrationFinished", "arch", "concurrentBuilds", "createdAt", "doNotTrack", "dualCerts", "fqdn", "id", "ipv4", "ipv6", "isAPIDebuggingEnabled", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "isTraefikUsed", "maxPort", "minPort", 3, "proxyDefaultRedirect", "sentryDSN", "updatedAt" FROM "Setting";
+DROP TABLE "Setting";
+ALTER TABLE "new_Setting" RENAME TO "Setting";
+CREATE UNIQUE INDEX "Setting_fqdn_key" ON "Setting"("fqdn");
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20221129130036_keep_local_docker_images/migration.sql b/apps/server/prisma/migrations/20221129130036_keep_local_docker_images/migration.sql
new file mode 100644
index 000000000..aa8136ed8
--- /dev/null
+++ b/apps/server/prisma/migrations/20221129130036_keep_local_docker_images/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Application" ADD COLUMN "gitCommitHash" TEXT;
diff --git a/apps/server/prisma/migrations/20221130142058_reconfigure_docker_registries/migration.sql b/apps/server/prisma/migrations/20221130142058_reconfigure_docker_registries/migration.sql
new file mode 100644
index 000000000..c77afb687
--- /dev/null
+++ b/apps/server/prisma/migrations/20221130142058_reconfigure_docker_registries/migration.sql
@@ -0,0 +1,66 @@
+/*
+ Warnings:
+
+ - You are about to drop the column `isSystemWide` on the `DockerRegistry` table. All the data in the column will be lost.
+
+*/
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_DockerRegistry" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "url" TEXT NOT NULL,
+ "username" TEXT,
+ "password" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "teamId" TEXT,
+ CONSTRAINT "DockerRegistry_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+INSERT INTO "new_DockerRegistry" ("createdAt", "id", "name", "password", "teamId", "updatedAt", "url", "username") SELECT "createdAt", "id", "name", "password", "teamId", "updatedAt", "url", "username" FROM "DockerRegistry";
+DROP TABLE "DockerRegistry";
+ALTER TABLE "new_DockerRegistry" RENAME TO "DockerRegistry";
+CREATE TABLE "new_Application" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "fqdn" TEXT,
+ "repository" TEXT,
+ "configHash" TEXT,
+ "branch" TEXT,
+ "buildPack" TEXT,
+ "projectId" INTEGER,
+ "port" INTEGER,
+ "exposePort" INTEGER,
+ "installCommand" TEXT,
+ "buildCommand" TEXT,
+ "startCommand" TEXT,
+ "baseDirectory" TEXT,
+ "publishDirectory" TEXT,
+ "deploymentType" TEXT,
+ "phpModules" TEXT,
+ "pythonWSGI" TEXT,
+ "pythonModule" TEXT,
+ "pythonVariable" TEXT,
+ "dockerFileLocation" TEXT,
+ "denoMainFile" TEXT,
+ "denoOptions" TEXT,
+ "dockerComposeFile" TEXT,
+ "dockerComposeFileLocation" TEXT,
+ "dockerComposeConfiguration" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "destinationDockerId" TEXT,
+ "gitSourceId" TEXT,
+ "gitCommitHash" TEXT,
+ "baseImage" TEXT,
+ "baseBuildImage" TEXT,
+ "dockerRegistryId" TEXT,
+ CONSTRAINT "Application_gitSourceId_fkey" FOREIGN KEY ("gitSourceId") REFERENCES "GitSource" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
+ CONSTRAINT "Application_destinationDockerId_fkey" FOREIGN KEY ("destinationDockerId") REFERENCES "DestinationDocker" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
+ CONSTRAINT "Application_dockerRegistryId_fkey" FOREIGN KEY ("dockerRegistryId") REFERENCES "DockerRegistry" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+INSERT INTO "new_Application" ("baseBuildImage", "baseDirectory", "baseImage", "branch", "buildCommand", "buildPack", "configHash", "createdAt", "denoMainFile", "denoOptions", "deploymentType", "destinationDockerId", "dockerComposeConfiguration", "dockerComposeFile", "dockerComposeFileLocation", "dockerFileLocation", "dockerRegistryId", "exposePort", "fqdn", "gitCommitHash", "gitSourceId", "id", "installCommand", "name", "phpModules", "port", "projectId", "publishDirectory", "pythonModule", "pythonVariable", "pythonWSGI", "repository", "startCommand", "updatedAt") SELECT "baseBuildImage", "baseDirectory", "baseImage", "branch", "buildCommand", "buildPack", "configHash", "createdAt", "denoMainFile", "denoOptions", "deploymentType", "destinationDockerId", "dockerComposeConfiguration", "dockerComposeFile", "dockerComposeFileLocation", "dockerFileLocation", "dockerRegistryId", "exposePort", "fqdn", "gitCommitHash", "gitSourceId", "id", "installCommand", "name", "phpModules", "port", "projectId", "publishDirectory", "pythonModule", "pythonVariable", "pythonWSGI", "repository", "startCommand", "updatedAt" FROM "Application";
+DROP TABLE "Application";
+ALTER TABLE "new_Application" RENAME TO "Application";
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/apps/server/prisma/migrations/20221201115801_simple_dockerfile_deployment/migration.sql b/apps/server/prisma/migrations/20221201115801_simple_dockerfile_deployment/migration.sql
new file mode 100644
index 000000000..b3406e59e
--- /dev/null
+++ b/apps/server/prisma/migrations/20221201115801_simple_dockerfile_deployment/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Application" ADD COLUMN "simpleDockerfile" TEXT;
diff --git a/apps/server/prisma/migrations/20221201133847_push_image_to_docker_registry/migration.sql b/apps/server/prisma/migrations/20221201133847_push_image_to_docker_registry/migration.sql
new file mode 100644
index 000000000..9f85d3518
--- /dev/null
+++ b/apps/server/prisma/migrations/20221201133847_push_image_to_docker_registry/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Application" ADD COLUMN "dockerRegistryImageName" TEXT;
diff --git a/apps/server/prisma/migrations/20221206140938_init/migration.sql b/apps/server/prisma/migrations/20221206140938_init/migration.sql
deleted file mode 100644
index 462efbd29..000000000
--- a/apps/server/prisma/migrations/20221206140938_init/migration.sql
+++ /dev/null
@@ -1,21 +0,0 @@
--- CreateTable
-CREATE TABLE "Category" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "name" TEXT NOT NULL,
- "budget" INTEGER NOT NULL,
- "customIcon" TEXT,
- "period" TEXT NOT NULL DEFAULT 'month',
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "updatedAt" DATETIME NOT NULL
-);
-
--- CreateTable
-CREATE TABLE "Transaction" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "amount" INTEGER NOT NULL,
- "description" TEXT,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "updatedAt" DATETIME NOT NULL,
- "categoryId" INTEGER NOT NULL,
- CONSTRAINT "Transaction_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "Category" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
-);
diff --git a/apps/server/prisma/schema.prisma b/apps/server/prisma/schema.prisma
index e0020544b..54eefc504 100644
--- a/apps/server/prisma/schema.prisma
+++ b/apps/server/prisma/schema.prisma
@@ -1,11 +1,705 @@
-// This is your Prisma schema file,
-// learn more about it in the docs: https://pris.ly/d/prisma-schema
-
generator client {
- provider = "prisma-client-js"
+ provider = "prisma-client-js"
+ binaryTargets = ["native"]
}
datasource db {
provider = "sqlite"
- url = env("DATABASE_URL")
+ url = env("COOLIFY_DATABASE_URL")
+}
+
+model Certificate {
+ id String @id @default(cuid())
+ key String
+ cert String
+ team Team? @relation(fields: [teamId], references: [id])
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ teamId String?
+}
+
+model Setting {
+ id String @id @default(cuid())
+ fqdn String? @unique
+ dualCerts Boolean @default(false)
+ minPort Int @default(9000)
+ maxPort Int @default(9100)
+ DNSServers String @default("1.1.1.1,8.8.8.8")
+ ipv4 String?
+ ipv6 String?
+ arch String?
+ concurrentBuilds Int @default(1)
+ applicationStoragePathMigrationFinished Boolean @default(false)
+ numberOfDockerImagesKeptLocally Int @default(3)
+ proxyDefaultRedirect String?
+ doNotTrack Boolean @default(false)
+ sentryDSN String?
+ previewSeparator String @default(".")
+ isAPIDebuggingEnabled Boolean @default(false)
+ isRegistrationEnabled Boolean @default(true)
+ isAutoUpdateEnabled Boolean @default(false)
+ isDNSCheckEnabled Boolean @default(true)
+ isTraefikUsed Boolean @default(true)
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+}
+
+model User {
+ id String @id @unique @default(cuid())
+ email String @unique
+ type String
+ password String?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ permission Permission[]
+ teams Team[]
+}
+
+model Permission {
+ id String @id @default(cuid())
+ userId String
+ teamId String
+ permission String
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ team Team @relation(fields: [teamId], references: [id])
+ user User @relation(fields: [userId], references: [id])
+}
+
+model Team {
+ id String @id @default(cuid())
+ name String?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ databaseId String?
+ serviceId String?
+ permissions Permission[]
+ sshKey SshKey[]
+ applications Application[]
+ database Database[]
+ destinationDocker DestinationDocker[]
+ gitSources GitSource[]
+ gitHubApps GithubApp[]
+ gitLabApps GitlabApp[]
+ service Service[]
+ users User[]
+ certificate Certificate[]
+ dockerRegistry DockerRegistry[]
+}
+
+model TeamInvitation {
+ id String @id @default(cuid())
+ uid String
+ email String
+ teamId String
+ teamName String
+ permission String
+ createdAt DateTime @default(now())
+}
+
+model Application {
+ id String @id @default(cuid())
+ name String
+ fqdn String?
+ repository String?
+ configHash String?
+ branch String?
+ buildPack String?
+ projectId Int?
+ port Int?
+ exposePort Int?
+ installCommand String?
+ buildCommand String?
+ startCommand String?
+ baseDirectory String?
+ publishDirectory String?
+ deploymentType String?
+ phpModules String?
+ pythonWSGI String?
+ pythonModule String?
+ pythonVariable String?
+ dockerFileLocation String?
+ denoMainFile String?
+ denoOptions String?
+ dockerComposeFile String?
+ dockerComposeFileLocation String?
+ dockerComposeConfiguration String?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ destinationDockerId String?
+ gitSourceId String?
+ gitCommitHash String?
+ baseImage String?
+ baseBuildImage String?
+ settings ApplicationSettings?
+ dockerRegistryId String?
+ dockerRegistryImageName String?
+ simpleDockerfile String?
+
+ persistentStorage ApplicationPersistentStorage[]
+ secrets Secret[]
+ teams Team[]
+ connectedDatabase ApplicationConnectedDatabase?
+ previewApplication PreviewApplication[]
+ gitSource GitSource? @relation(fields: [gitSourceId], references: [id])
+ destinationDocker DestinationDocker? @relation(fields: [destinationDockerId], references: [id])
+ dockerRegistry DockerRegistry? @relation(fields: [dockerRegistryId], references: [id])
+}
+
+model PreviewApplication {
+ id String @id @default(cuid())
+ pullmergeRequestId String
+ sourceBranch String
+ isRandomDomain Boolean @default(false)
+ customDomain String?
+ applicationId String
+ application Application @relation(fields: [applicationId], references: [id])
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+}
+
+model ApplicationConnectedDatabase {
+ id String @id @default(cuid())
+ applicationId String @unique
+ databaseId String?
+ hostedDatabaseType String?
+ hostedDatabaseHost String?
+ hostedDatabasePort Int?
+ hostedDatabaseName String?
+ hostedDatabaseUser String?
+ hostedDatabasePassword String?
+ hostedDatabaseDBName String?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ database Database? @relation(fields: [databaseId], references: [id])
+ application Application @relation(fields: [applicationId], references: [id])
+}
+
+model ApplicationSettings {
+ id String @id @default(cuid())
+ applicationId String @unique
+ dualCerts Boolean @default(false)
+ debug Boolean @default(false)
+ previews Boolean @default(false)
+ autodeploy Boolean @default(true)
+ isBot Boolean @default(false)
+ isPublicRepository Boolean @default(false)
+ isDBBranching Boolean @default(false)
+ isCustomSSL Boolean @default(false)
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ application Application @relation(fields: [applicationId], references: [id])
+}
+
+model ApplicationPersistentStorage {
+ id String @id @default(cuid())
+ applicationId String
+ path String
+ oldPath Boolean @default(false)
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ application Application @relation(fields: [applicationId], references: [id])
+
+ @@unique([applicationId, path])
+}
+
+model ServicePersistentStorage {
+ id String @id @default(cuid())
+ serviceId String
+ path String
+ volumeName String?
+ predefined Boolean @default(false)
+ containerId String?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ service Service @relation(fields: [serviceId], references: [id])
+
+ @@unique([serviceId, containerId, path])
+}
+
+model Secret {
+ id String @id @default(cuid())
+ name String
+ value String
+ isPRMRSecret Boolean @default(false)
+ isBuildSecret Boolean @default(false)
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ applicationId String
+ application Application @relation(fields: [applicationId], references: [id])
+
+ @@unique([name, applicationId, isPRMRSecret])
+}
+
+model ServiceSecret {
+ id String @id @default(cuid())
+ name String
+ value String
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ serviceId String
+ service Service @relation(fields: [serviceId], references: [id])
+
+ @@unique([name, serviceId])
+}
+
+model BuildLog {
+ id String @id @default(cuid())
+ applicationId String?
+ buildId String
+ line String
+ time BigInt
+}
+
+model Build {
+ id String @id @default(cuid())
+ type String
+ applicationId String?
+ destinationDockerId String?
+ gitSourceId String?
+ githubAppId String?
+ gitlabAppId String?
+ commit String?
+ pullmergeRequestId String?
+ previewApplicationId String?
+ forceRebuild Boolean @default(false)
+ sourceBranch String?
+ sourceRepository String?
+ branch String?
+ status String? @default("queued")
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+}
+
+model DestinationDocker {
+ id String @id @default(cuid())
+ network String @unique
+ name String
+ engine String?
+ remoteEngine Boolean @default(false)
+ remoteIpAddress String?
+ remoteUser String?
+ remotePort Int?
+ remoteVerified Boolean @default(false)
+ isCoolifyProxyUsed Boolean? @default(false)
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ sshKeyId String?
+ sshKey SshKey? @relation(fields: [sshKeyId], references: [id])
+ sshLocalPort Int?
+ application Application[]
+ database Database[]
+ service Service[]
+ teams Team[]
+}
+
+model SshKey {
+ id String @id @default(cuid())
+ name String
+ privateKey String
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ teamId String?
+ team Team? @relation(fields: [teamId], references: [id])
+ destinationDocker DestinationDocker[]
+}
+
+model DockerRegistry {
+ id String @id @default(cuid())
+ name String
+ url String
+ username String?
+ password String?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ teamId String?
+ team Team? @relation(fields: [teamId], references: [id])
+ application Application[]
+}
+
+model GitSource {
+ id String @id @default(cuid())
+ name String
+ forPublic Boolean @default(false)
+ type String?
+ apiUrl String?
+ htmlUrl String?
+ customPort Int @default(22)
+ organization String?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ githubAppId String? @unique
+ gitlabAppId String? @unique
+ isSystemWide Boolean @default(false)
+ gitlabApp GitlabApp? @relation(fields: [gitlabAppId], references: [id])
+ githubApp GithubApp? @relation(fields: [githubAppId], references: [id])
+ application Application[]
+ teams Team[]
+}
+
+model GithubApp {
+ id String @id @default(cuid())
+ name String? @unique
+ appId Int?
+ installationId Int?
+ clientId String?
+ clientSecret String?
+ webhookSecret String?
+ privateKey String?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ gitSource GitSource?
+ teams Team[]
+}
+
+model GitlabApp {
+ id String @id @default(cuid())
+ oauthId Int @unique
+ groupName String? @unique
+ deployKeyId Int?
+ privateSshKey String?
+ publicSshKey String?
+ webhookToken String?
+ appId String?
+ appSecret String?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ gitSource GitSource?
+ teams Team[]
+}
+
+model Database {
+ id String @id @default(cuid())
+ name String
+ publicPort Int?
+ defaultDatabase String?
+ type String?
+ version String?
+ dbUser String?
+ dbUserPassword String?
+ rootUser String?
+ rootUserPassword String?
+ destinationDockerId String?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ destinationDocker DestinationDocker? @relation(fields: [destinationDockerId], references: [id])
+ settings DatabaseSettings?
+ teams Team[]
+ applicationConnectedDatabase ApplicationConnectedDatabase[]
+ databaseSecret DatabaseSecret[]
+}
+
+model DatabaseSecret {
+ id String @id @default(cuid())
+ name String
+ value String
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ databaseId String
+ database Database @relation(fields: [databaseId], references: [id])
+
+ @@unique([name, databaseId])
+}
+
+model DatabaseSettings {
+ id String @id @default(cuid())
+ databaseId String @unique
+ isPublic Boolean @default(false)
+ appendOnly Boolean @default(true)
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ database Database @relation(fields: [databaseId], references: [id])
+}
+
+model Service {
+ id String @id @default(cuid())
+ name String
+ fqdn String?
+ exposePort Int?
+ dualCerts Boolean @default(false)
+ type String?
+ version String?
+ templateVersion String @default("0.0.0")
+ destinationDockerId String?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ destinationDocker DestinationDocker? @relation(fields: [destinationDockerId], references: [id])
+ persistentStorage ServicePersistentStorage[]
+ serviceSecret ServiceSecret[]
+ serviceSetting ServiceSetting[]
+ teams Team[]
+
+ fider Fider?
+ ghost Ghost?
+ glitchTip GlitchTip?
+ hasura Hasura?
+ meiliSearch MeiliSearch?
+ minio Minio?
+ moodle Moodle?
+ plausibleAnalytics PlausibleAnalytics?
+ umami Umami?
+ vscodeserver Vscodeserver?
+ wordpress Wordpress?
+ appwrite Appwrite?
+ searxng Searxng?
+ weblate Weblate?
+ taiga Taiga?
+}
+
+model ServiceSetting {
+ id String @id @default(cuid())
+ serviceId String
+ name String
+ value String
+ variableName String
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ service Service @relation(fields: [serviceId], references: [id])
+
+ @@unique([serviceId, name])
+}
+
+model PlausibleAnalytics {
+ id String @id @default(cuid())
+ email String?
+ username String?
+ password String
+ postgresqlUser String
+ postgresqlPassword String
+ postgresqlDatabase String
+ postgresqlPublicPort Int?
+ secretKeyBase String?
+ scriptName String @default("plausible.js")
+ serviceId String @unique
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ service Service @relation(fields: [serviceId], references: [id])
+}
+
+model Minio {
+ id String @id @default(cuid())
+ rootUser String
+ rootUserPassword String
+ publicPort Int?
+ apiFqdn String?
+ serviceId String @unique
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ service Service @relation(fields: [serviceId], references: [id])
+}
+
+model Vscodeserver {
+ id String @id @default(cuid())
+ password String
+ serviceId String @unique
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ service Service @relation(fields: [serviceId], references: [id])
+}
+
+model Wordpress {
+ id String @id @default(cuid())
+ extraConfig String?
+ tablePrefix String?
+ ownMysql Boolean @default(false)
+ mysqlHost String?
+ mysqlPort Int?
+ mysqlUser String?
+ mysqlPassword String?
+ mysqlRootUser String?
+ mysqlRootUserPassword String?
+ mysqlDatabase String?
+ mysqlPublicPort Int?
+ ftpEnabled Boolean @default(false)
+ ftpUser String?
+ ftpPassword String?
+ ftpPublicPort Int?
+ ftpHostKey String?
+ ftpHostKeyPrivate String?
+ serviceId String @unique
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ service Service @relation(fields: [serviceId], references: [id])
+}
+
+model Ghost {
+ id String @id @default(cuid())
+ defaultEmail String
+ defaultPassword String
+ mariadbUser String
+ mariadbPassword String
+ mariadbRootUser String
+ mariadbRootUserPassword String
+ mariadbDatabase String?
+ mariadbPublicPort Int?
+ serviceId String @unique
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ service Service @relation(fields: [serviceId], references: [id])
+}
+
+model MeiliSearch {
+ id String @id @default(cuid())
+ masterKey String
+ serviceId String @unique
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ service Service @relation(fields: [serviceId], references: [id])
+}
+
+model Umami {
+ id String @id @default(cuid())
+ serviceId String @unique
+ postgresqlUser String
+ postgresqlPassword String
+ postgresqlDatabase String
+ postgresqlPublicPort Int?
+ umamiAdminPassword String
+ hashSalt String
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ service Service @relation(fields: [serviceId], references: [id])
+}
+
+model Hasura {
+ id String @id @default(cuid())
+ serviceId String @unique
+ postgresqlUser String
+ postgresqlPassword String
+ postgresqlDatabase String
+ postgresqlPublicPort Int?
+ graphQLAdminPassword String
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ service Service @relation(fields: [serviceId], references: [id])
+}
+
+model Fider {
+ id String @id @default(cuid())
+ serviceId String @unique
+ postgresqlUser String
+ postgresqlPassword String
+ postgresqlDatabase String
+ postgresqlPublicPort Int?
+ jwtSecret String
+ emailNoreply String?
+ emailMailgunApiKey String?
+ emailMailgunDomain String?
+ emailMailgunRegion String @default("EU")
+ emailSmtpHost String?
+ emailSmtpPort Int?
+ emailSmtpUser String?
+ emailSmtpPassword String?
+ emailSmtpEnableStartTls Boolean @default(false)
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ service Service @relation(fields: [serviceId], references: [id])
+}
+
+model Moodle {
+ id String @id @default(cuid())
+ serviceId String @unique
+ defaultUsername String
+ defaultPassword String
+ defaultEmail String
+ mariadbUser String
+ mariadbPassword String
+ mariadbRootUser String
+ mariadbRootUserPassword String
+ mariadbDatabase String
+ mariadbPublicPort Int?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ service Service @relation(fields: [serviceId], references: [id])
+}
+
+model Appwrite {
+ id String @id @default(cuid())
+ serviceId String @unique
+ opensslKeyV1 String
+ executorSecret String
+ redisPassword String
+ mariadbHost String?
+ mariadbPort Int @default(3306)
+ mariadbUser String
+ mariadbPassword String
+ mariadbRootUser String
+ mariadbRootUserPassword String
+ mariadbDatabase String
+ mariadbPublicPort Int?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ service Service @relation(fields: [serviceId], references: [id])
+}
+
+model GlitchTip {
+ id String @id @default(cuid())
+ postgresqlUser String
+ postgresqlPassword String
+ postgresqlDatabase String
+ postgresqlPublicPort Int?
+ secretKeyBase String?
+ defaultEmail String
+ defaultUsername String
+ defaultPassword String
+ defaultEmailFrom String @default("glitchtip@domain.tdl")
+ emailSmtpHost String? @default("domain.tdl")
+ emailSmtpPort Int? @default(25)
+ emailSmtpUser String?
+ emailSmtpPassword String?
+ emailSmtpUseTls Boolean @default(false)
+ emailSmtpUseSsl Boolean @default(false)
+ emailBackend String?
+ mailgunApiKey String?
+ sendgridApiKey String?
+ enableOpenUserRegistration Boolean @default(true)
+ serviceId String @unique
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ service Service @relation(fields: [serviceId], references: [id])
+}
+
+model Searxng {
+ id String @id @default(cuid())
+ secretKey String
+ redisPassword String
+ serviceId String @unique
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ service Service @relation(fields: [serviceId], references: [id])
+}
+
+model Weblate {
+ id String @id @default(cuid())
+ adminPassword String
+ postgresqlHost String
+ postgresqlPort Int
+ postgresqlUser String
+ postgresqlPassword String
+ postgresqlDatabase String
+ postgresqlPublicPort Int?
+ serviceId String @unique
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ service Service @relation(fields: [serviceId], references: [id])
+}
+
+model Taiga {
+ id String @id @default(cuid())
+ secretKey String
+ erlangSecret String
+ djangoAdminPassword String
+ djangoAdminUser String
+ rabbitMQUser String
+ rabbitMQPassword String
+ postgresqlHost String
+ postgresqlPort Int
+ postgresqlUser String
+ postgresqlPassword String
+ postgresqlDatabase String
+ postgresqlPublicPort Int?
+ serviceId String @unique
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ service Service @relation(fields: [serviceId], references: [id])
}
diff --git a/apps/server/prisma/seed.js b/apps/server/prisma/seed.js
new file mode 100644
index 000000000..3d4b16a28
--- /dev/null
+++ b/apps/server/prisma/seed.js
@@ -0,0 +1,113 @@
+const dotEnvExtended = require('dotenv-extended');
+dotEnvExtended.load();
+const crypto = require('crypto');
+const { PrismaClient } = require('@prisma/client');
+const prisma = new PrismaClient();
+const algorithm = 'aes-256-ctr';
+
+async function main() {
+ // Enable registration for the first user
+ const settingsFound = await prisma.setting.findFirst({});
+ if (!settingsFound) {
+ await prisma.setting.create({
+ data: {
+ id: '0',
+ arch: process.arch,
+ }
+ });
+ } else {
+ await prisma.setting.update({
+ where: {
+ id: settingsFound.id
+ },
+ data: {
+ id: '0'
+ }
+ });
+ }
+ // Create local docker engine
+ const localDocker = await prisma.destinationDocker.findFirst({
+ where: { engine: '/var/run/docker.sock' }
+ });
+ if (!localDocker) {
+ await prisma.destinationDocker.create({
+ data: {
+ engine: '/var/run/docker.sock',
+ name: 'Local Docker',
+ isCoolifyProxyUsed: true,
+ network: 'coolify'
+ }
+ });
+ }
+
+ // Set auto-update based on env variable
+ const isAutoUpdateEnabled = process.env['COOLIFY_AUTO_UPDATE'] === 'true';
+ await prisma.setting.update({
+ where: {
+ id: '0'
+ },
+ data: {
+ isAutoUpdateEnabled
+ }
+ });
+ // Create public github source
+ const github = await prisma.gitSource.findFirst({
+ where: { htmlUrl: 'https://github.com', forPublic: true }
+ });
+ if (!github) {
+ await prisma.gitSource.create({
+ data: {
+ apiUrl: 'https://api.github.com',
+ htmlUrl: 'https://github.com',
+ forPublic: true,
+ name: 'Github Public',
+ type: 'github'
+ }
+ });
+ }
+ // Create public gitlab source
+ const gitlab = await prisma.gitSource.findFirst({
+ where: { htmlUrl: 'https://gitlab.com', forPublic: true }
+ });
+ if (!gitlab) {
+ await prisma.gitSource.create({
+ data: {
+ apiUrl: 'https://gitlab.com/api/v4',
+ htmlUrl: 'https://gitlab.com',
+ forPublic: true,
+ name: 'Gitlab Public',
+ type: 'gitlab'
+ }
+ });
+ }
+ // Set new preview secrets
+ const secrets = await prisma.secret.findMany({ where: { isPRMRSecret: false } })
+ if (secrets.length > 0) {
+ for (const secret of secrets) {
+ const previewSecrets = await prisma.secret.findMany({ where: { applicationId: secret.applicationId, name: secret.name, isPRMRSecret: true } })
+ if (previewSecrets.length === 0) {
+ await prisma.secret.create({ data: { ...secret, id: undefined, isPRMRSecret: true } })
+ }
+ }
+ }
+}
+main()
+ .catch((e) => {
+ console.error(e);
+ process.exit(1);
+ })
+ .finally(async () => {
+ await prisma.$disconnect();
+ });
+
+const encrypt = (text) => {
+ if (text) {
+ const iv = crypto.randomBytes(16);
+ const cipher = crypto.createCipheriv(algorithm, process.env['COOLIFY_SECRET_KEY'], iv);
+ const encrypted = Buffer.concat([cipher.update(text), cipher.final()]);
+ return JSON.stringify({
+ iv: iv.toString('hex'),
+ content: encrypted.toString('hex')
+ });
+ }
+};
\ No newline at end of file
diff --git a/apps/server/src/api/index.ts b/apps/server/src/api/index.ts
new file mode 100644
index 000000000..b47d8358c
--- /dev/null
+++ b/apps/server/src/api/index.ts
@@ -0,0 +1,8 @@
+import type { FastifyPluginAsync } from 'fastify';
+
+const root: FastifyPluginAsync = async (fastify): Promise
=> {
+ fastify.get('/', async function (_request, _reply) {
+ return { status: 'ok' };
+ });
+};
+export default root;
diff --git a/apps/server/src/config/index.ts b/apps/server/src/config.ts
similarity index 65%
rename from apps/server/src/config/index.ts
rename to apps/server/src/config.ts
index 9b139c5bd..e45c2a4bd 100644
--- a/apps/server/src/config/index.ts
+++ b/apps/server/src/config.ts
@@ -1,4 +1,4 @@
-import type { ServerOptions } from '../server';
+import type { ServerOptions } from './server';
export const serverConfig: ServerOptions = {
dev: false,
diff --git a/apps/server/src/env.js b/apps/server/src/env.js
index cbe1c25db..f69754110 100644
--- a/apps/server/src/env.js
+++ b/apps/server/src/env.js
@@ -1,9 +1,17 @@
+const dotenv = require('dotenv');
+const isDev = process.env.NODE_ENV === 'development';
+// dotenv.config({ path: isDev ? '../../.env' : '.env' });
+dotenv.config();
const { z } = require('zod');
/*eslint sort-keys: "error"*/
const envSchema = z.object({
+ CODESANDBOX_HOST: z.string().optional(),
NODE_ENV: z.enum(['development', 'test', 'production']),
- COOLIFY_SECRET_KEY: z.string()
+ COOLIFY_DATABASE_URL: z.string(),
+ COOLIFY_SECRET_KEY: z.string().length(32),
+ COOLIFY_WHITE_LABELED: z.string().optional(),
+ COOLIFY_WHITE_LABELED_ICON: z.string().optional()
});
const env = envSchema.safeParse(process.env);
diff --git a/apps/server/src/lib/common.ts b/apps/server/src/lib/common.ts
new file mode 100644
index 000000000..77b73b284
--- /dev/null
+++ b/apps/server/src/lib/common.ts
@@ -0,0 +1,111 @@
+import type { Permission, Setting, Team, TeamInvitation, User } from '@prisma/client';
+import { prisma } from '../prisma';
+import bcrypt from 'bcryptjs';
+import crypto from 'crypto';
+import fs from 'fs/promises';
+import { uniqueNamesGenerator, adjectives, colors, animals } from 'unique-names-generator';
+import type { Config } from 'unique-names-generator';
+import { env } from '../env';
+import { day } from './dayjs';
+
+const customConfig: Config = {
+ dictionaries: [adjectives, colors, animals],
+ style: 'capital',
+ separator: ' ',
+ length: 3
+};
+const algorithm = 'aes-256-ctr';
+export const isDev = env.NODE_ENV === 'development';
+export const version = '3.13.0';
+export const sentryDSN =
+ 'https://409f09bcb7af47928d3e0f46b78987f3@o1082494.ingest.sentry.io/4504236622217216';
+
+export async function listSettings(): Promise {
+ return await prisma.setting.findUnique({ where: { id: '0' } });
+}
+export async function getCurrentUser(
+ userId: string
+): Promise<(User & { permission: Permission[]; teams: Team[] }) | null> {
+ return await prisma.user.findUnique({
+ where: { id: userId },
+ include: { teams: true, permission: true }
+ });
+}
+export async function getTeamInvitation(userId: string): Promise {
+ return await prisma.teamInvitation.findMany({ where: { uid: userId } });
+}
+
+export async function hashPassword(password: string): Promise {
+ const saltRounds = 15;
+ return bcrypt.hash(password, saltRounds);
+}
+export async function comparePassword(password: string, hashedPassword: string): Promise {
+ return bcrypt.compare(password, hashedPassword);
+}
+export const uniqueName = (): string => uniqueNamesGenerator(customConfig);
+
+export const decrypt = (hashString: string) => {
+ if (hashString) {
+ try {
+ const hash = JSON.parse(hashString);
+ const decipher = crypto.createDecipheriv(
+ algorithm,
+ env.COOLIFY_SECRET_KEY,
+ Buffer.from(hash.iv, 'hex')
+ );
+ const decrpyted = Buffer.concat([
+ decipher.update(Buffer.from(hash.content, 'hex')),
+ decipher.final()
+ ]);
+ return decrpyted.toString();
+ } catch (error) {
+ if (error instanceof Error) {
+ console.log({ decryptionError: error.message });
+ }
+ return hashString;
+ }
+ }
+ return false;
+};
+
+export function generateRangeArray(start, end) {
+ return Array.from({ length: end - start }, (v, k) => k + start);
+}
+export function generateTimestamp(): string {
+ return `${day().format('HH:mm:ss.SSS')}`;
+}
+export const encrypt = (text: string) => {
+ if (text) {
+ const iv = crypto.randomBytes(16);
+ const cipher = crypto.createCipheriv(algorithm, env.COOLIFY_SECRET_KEY, iv);
+ const encrypted = Buffer.concat([cipher.update(text.trim()), cipher.final()]);
+ return JSON.stringify({
+ iv: iv.toString('hex'),
+ content: encrypted.toString('hex')
+ });
+ }
+ return false;
+};
+
+export async function getTemplates() {
+ const templatePath = isDev ? './templates.json' : '/app/templates.json';
+ const open = await fs.open(templatePath, 'r');
+ try {
+ let data = await open.readFile({ encoding: 'utf-8' });
+ let jsonData = JSON.parse(data);
+ if (isARM(process.arch)) {
+ jsonData = jsonData.filter((d) => d.arch !== 'amd64');
+ }
+ return jsonData;
+ } catch (error) {
+ return [];
+ } finally {
+ await open?.close();
+ }
+}
+export function isARM(arch: string) {
+ if (arch === 'arm' || arch === 'arm64' || arch === 'aarch' || arch === 'aarch64') {
+ return true;
+ }
+ return false;
+}
diff --git a/apps/server/src/lib/dayjs.ts b/apps/server/src/lib/dayjs.ts
new file mode 100644
index 000000000..9ff5b0a1a
--- /dev/null
+++ b/apps/server/src/lib/dayjs.ts
@@ -0,0 +1,7 @@
+import dayjs from 'dayjs';
+import utc from 'dayjs/plugin/utc.js';
+import relativeTime from 'dayjs/plugin/relativeTime.js';
+dayjs.extend(utc);
+dayjs.extend(relativeTime);
+
+export { dayjs as day };
diff --git a/apps/server/src/lib/docker.ts b/apps/server/src/lib/docker.ts
new file mode 100644
index 000000000..27bf380a3
--- /dev/null
+++ b/apps/server/src/lib/docker.ts
@@ -0,0 +1,47 @@
+import { executeCommand } from "./executeCommand";
+
+export async function checkContainer({ dockerId, container, remove = false }: { dockerId: string, container: string, remove?: boolean }): Promise<{ found: boolean, status?: { isExited: boolean, isRunning: boolean, isRestarting: boolean } }> {
+ let containerFound = false;
+ try {
+ const { stdout } = await executeCommand({
+ dockerId,
+ command:
+ `docker inspect --format '{{json .State}}' ${container}`
+ });
+ containerFound = true
+ const parsedStdout = JSON.parse(stdout);
+ const status = parsedStdout.Status;
+ const isRunning = status === 'running';
+ const isRestarting = status === 'restarting'
+ const isExited = status === 'exited'
+ if (status === 'created') {
+ await executeCommand({
+ dockerId,
+ command:
+ `docker rm ${container}`
+ });
+ }
+ if (remove && status === 'exited') {
+ await executeCommand({
+ dockerId,
+ command:
+ `docker rm ${container}`
+ });
+ }
+
+ return {
+ found: containerFound,
+ status: {
+ isRunning,
+ isRestarting,
+ isExited
+ }
+ };
+ } catch (err) {
+ // Container not found
+ }
+ return {
+ found: false
+ };
+
+}
\ No newline at end of file
diff --git a/apps/server/src/lib/executeCommand.ts b/apps/server/src/lib/executeCommand.ts
new file mode 100644
index 000000000..198c4046c
--- /dev/null
+++ b/apps/server/src/lib/executeCommand.ts
@@ -0,0 +1,188 @@
+import { prisma } from '../prisma';
+import os from 'os';
+import fs from 'fs/promises';
+import type { ExecaChildProcess } from 'execa';
+import sshConfig from 'ssh-config';
+
+import { getFreeSSHLocalPort } from './ssh';
+import { env } from '../env';
+import { saveBuildLog } from './logging';
+import { decrypt } from './common';
+
+export async function executeCommand({
+ command,
+ dockerId = null,
+ sshCommand = false,
+ shell = false,
+ stream = false,
+ buildId,
+ applicationId,
+ debug
+}: {
+ command: string;
+ sshCommand?: boolean;
+ shell?: boolean;
+ stream?: boolean;
+ dockerId?: string;
+ buildId?: string;
+ applicationId?: string;
+ debug?: boolean;
+}): Promise> {
+ const { execa, execaCommand } = await import('execa');
+ const { parse } = await import('shell-quote');
+ const parsedCommand = parse(command);
+ const dockerCommand = parsedCommand[0];
+ const dockerArgs = parsedCommand.slice(1);
+
+ if (dockerId) {
+ const destinationDocker = await prisma.destinationDocker.findUnique({
+ where: { id: dockerId }
+ });
+ if (!destinationDocker) {
+ throw new Error('Destination docker not found');
+ }
+ let { remoteEngine, remoteIpAddress, engine } = destinationDocker;
+ if (remoteEngine) {
+ await createRemoteEngineConfiguration(dockerId);
+ engine = `ssh://${remoteIpAddress}-remote`;
+ } else {
+ engine = 'unix:///var/run/docker.sock';
+ }
+ if (env.CODESANDBOX_HOST) {
+ if (command.startsWith('docker compose')) {
+ command = command.replace(/docker compose/gi, 'docker-compose');
+ }
+ }
+ if (sshCommand) {
+ if (shell) {
+ return execaCommand(`ssh ${remoteIpAddress}-remote ${command}`);
+ }
+ return await execa('ssh', [`${remoteIpAddress}-remote`, dockerCommand, ...dockerArgs]);
+ }
+ if (stream) {
+ return await new Promise(async (resolve, reject) => {
+ let subprocess = null;
+ if (shell) {
+ subprocess = execaCommand(command, {
+ env: { DOCKER_BUILDKIT: '1', DOCKER_HOST: engine }
+ });
+ } else {
+ subprocess = execa(dockerCommand, dockerArgs, {
+ env: { DOCKER_BUILDKIT: '1', DOCKER_HOST: engine }
+ });
+ }
+ const logs: any[] = [];
+ if (subprocess && subprocess.stdout && subprocess.stderr) {
+ subprocess.stdout.on('data', async (data) => {
+ const stdout = data.toString();
+ const array = stdout.split('\n');
+ for (const line of array) {
+ if (line !== '\n' && line !== '') {
+ const log = {
+ line: `${line.replace('\n', '')}`,
+ buildId,
+ applicationId
+ };
+ logs.push(log);
+ if (debug) {
+ await saveBuildLog(log);
+ }
+ }
+ }
+ });
+ subprocess.stderr.on('data', async (data) => {
+ const stderr = data.toString();
+ const array = stderr.split('\n');
+ for (const line of array) {
+ if (line !== '\n' && line !== '') {
+ const log = {
+ line: `${line.replace('\n', '')}`,
+ buildId,
+ applicationId
+ };
+ logs.push(log);
+ if (debug) {
+ await saveBuildLog(log);
+ }
+ }
+ }
+ });
+ subprocess.on('exit', async (code) => {
+ if (code === 0) {
+ resolve('success');
+ } else {
+ if (!debug) {
+ for (const log of logs) {
+ await saveBuildLog(log);
+ }
+ }
+ reject(code);
+ }
+ });
+ }
+ });
+ } else {
+ if (shell) {
+ return await execaCommand(command, {
+ env: { DOCKER_BUILDKIT: '1', DOCKER_HOST: engine }
+ });
+ } else {
+ return await execa(dockerCommand, dockerArgs, {
+ env: { DOCKER_BUILDKIT: '1', DOCKER_HOST: engine }
+ });
+ }
+ }
+ } else {
+ if (shell) {
+ return execaCommand(command, { shell: true });
+ }
+ return await execa(dockerCommand, dockerArgs);
+ }
+}
+
+export async function createRemoteEngineConfiguration(id: string) {
+ const homedir = os.homedir();
+ const sshKeyFile = `/tmp/id_rsa-${id}`;
+ const localPort = await getFreeSSHLocalPort(id);
+ const {
+ sshKey: { privateKey },
+ network,
+ remoteIpAddress,
+ remotePort,
+ remoteUser
+ } = await prisma.destinationDocker.findFirst({ where: { id }, include: { sshKey: true } });
+ await fs.writeFile(sshKeyFile, decrypt(privateKey) + '\n', { encoding: 'utf8', mode: 400 });
+ const config = sshConfig.parse('');
+ const Host = `${remoteIpAddress}-remote`;
+
+ try {
+ await executeCommand({ command: `ssh-keygen -R ${Host}` });
+ await executeCommand({ command: `ssh-keygen -R ${remoteIpAddress}` });
+ await executeCommand({ command: `ssh-keygen -R localhost:${localPort}` });
+ } catch (error) {}
+
+ const found = config.find({ Host });
+ const foundIp = config.find({ Host: remoteIpAddress });
+
+ if (found) config.remove({ Host });
+ if (foundIp) config.remove({ Host: remoteIpAddress });
+
+ config.append({
+ Host,
+ Hostname: remoteIpAddress,
+ Port: remotePort.toString(),
+ User: remoteUser,
+ StrictHostKeyChecking: 'no',
+ IdentityFile: sshKeyFile,
+ ControlMaster: 'auto',
+ ControlPath: `${homedir}/.ssh/coolify-${remoteIpAddress}-%r@%h:%p`,
+ ControlPersist: '10m'
+ });
+
+ try {
+ await fs.stat(`${homedir}/.ssh/`);
+ } catch (error) {
+ await fs.mkdir(`${homedir}/.ssh/`);
+ }
+ return await fs.writeFile(`${homedir}/.ssh/config`, sshConfig.stringify(config));
+}
diff --git a/apps/server/src/lib/logging.ts b/apps/server/src/lib/logging.ts
new file mode 100644
index 000000000..c8f460402
--- /dev/null
+++ b/apps/server/src/lib/logging.ts
@@ -0,0 +1,50 @@
+import { prisma } from '../prisma';
+import { encrypt, generateTimestamp, isDev } from './common';
+import { day } from './dayjs';
+
+export const saveBuildLog = async ({
+ line,
+ buildId,
+ applicationId
+}: {
+ line: string;
+ buildId: string;
+ applicationId: string;
+}): Promise => {
+ if (buildId === 'undefined' || buildId === 'null' || !buildId) return;
+ if (applicationId === 'undefined' || applicationId === 'null' || !applicationId) return;
+ const { default: got } = await import('got');
+ if (typeof line === 'object' && line) {
+ if (line.shortMessage) {
+ line = line.shortMessage + '\n' + line.stderr;
+ } else {
+ line = JSON.stringify(line);
+ }
+ }
+ if (line && typeof line === 'string' && line.includes('ghs_')) {
+ const regex = /ghs_.*@/g;
+ line = line.replace(regex, '@');
+ }
+ const addTimestamp = `[${generateTimestamp()}] ${line}`;
+ const fluentBitUrl = isDev ? 'http://localhost:24224' : 'http://coolify-fluentbit:24224';
+
+ if (isDev) {
+ console.debug(`[${applicationId}] ${addTimestamp}`);
+ }
+ try {
+ return await got.post(`${fluentBitUrl}/${applicationId}_buildlog_${buildId}.csv`, {
+ json: {
+ line: encrypt(line)
+ }
+ });
+ } catch (error) {
+ return await prisma.buildLog.create({
+ data: {
+ line: addTimestamp,
+ buildId,
+ time: Number(day().valueOf()),
+ applicationId
+ }
+ });
+ }
+};
diff --git a/apps/server/src/lib/ssh.ts b/apps/server/src/lib/ssh.ts
new file mode 100644
index 000000000..77cbf7307
--- /dev/null
+++ b/apps/server/src/lib/ssh.ts
@@ -0,0 +1,47 @@
+import { prisma } from '../prisma';
+import { generateRangeArray } from './common';
+
+export async function getFreeSSHLocalPort(id: string): Promise {
+ const { default: isReachable } = await import('is-port-reachable');
+ const { remoteIpAddress, sshLocalPort } = await prisma.destinationDocker.findUnique({
+ where: { id }
+ });
+ if (sshLocalPort) {
+ return Number(sshLocalPort);
+ }
+
+ const data = await prisma.setting.findFirst();
+ const { minPort, maxPort } = data;
+
+ const ports = await prisma.destinationDocker.findMany({
+ where: { sshLocalPort: { not: null }, remoteIpAddress: { not: remoteIpAddress } }
+ });
+
+ const alreadyConfigured = await prisma.destinationDocker.findFirst({
+ where: {
+ remoteIpAddress,
+ id: { not: id },
+ sshLocalPort: { not: null }
+ }
+ });
+ if (alreadyConfigured?.sshLocalPort) {
+ await prisma.destinationDocker.update({
+ where: { id },
+ data: { sshLocalPort: alreadyConfigured.sshLocalPort }
+ });
+ return Number(alreadyConfigured.sshLocalPort);
+ }
+ const range = generateRangeArray(minPort, maxPort);
+ const availablePorts = range.filter((port) => !ports.map((p) => p.sshLocalPort).includes(port));
+ for (const port of availablePorts) {
+ const found = await isReachable(port, { host: 'localhost' });
+ if (!found) {
+ await prisma.destinationDocker.update({
+ where: { id },
+ data: { sshLocalPort: Number(port) }
+ });
+ return Number(port);
+ }
+ }
+ return false;
+}
diff --git a/apps/server/src/prisma.ts b/apps/server/src/prisma.ts
index a384c202c..e315eae42 100644
--- a/apps/server/src/prisma.ts
+++ b/apps/server/src/prisma.ts
@@ -6,16 +6,15 @@ import { env } from './env';
import { PrismaClient } from '@prisma/client';
const prismaGlobal = global as typeof global & {
- prisma?: PrismaClient;
+ prisma?: PrismaClient;
};
export const prisma: PrismaClient =
- prismaGlobal.prisma ||
- new PrismaClient({
- log:
- env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'],
- });
+ prismaGlobal.prisma ||
+ new PrismaClient({
+ log: env.NODE_ENV === 'developments' ? ['query', 'error', 'warn'] : ['error']
+ });
if (env.NODE_ENV !== 'production') {
- prismaGlobal.prisma = prisma;
-}
\ No newline at end of file
+ prismaGlobal.prisma = prisma;
+}
diff --git a/apps/server/src/router/index.ts b/apps/server/src/router/index.ts
deleted file mode 100644
index cf362f41d..000000000
--- a/apps/server/src/router/index.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { apiRouter } from './routers/api';
-import { router } from './trpc';
-
-export const appRouter = router({
- api: apiRouter,
-});
-
-export type AppRouter = typeof appRouter;
diff --git a/apps/server/src/router/routers/api.ts b/apps/server/src/router/routers/api.ts
deleted file mode 100644
index 685e0339a..000000000
--- a/apps/server/src/router/routers/api.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-// import { z } from 'zod';
-import { publicProcedure, router } from '../trpc';
-// import { prisma } from '../../prisma';
-import { TRPCError } from '@trpc/server';
-
-export const apiRouter = router({
- getConnection: publicProcedure.query(async () => {
- try {
- return { success: true };
- } catch (error) {
- throw new TRPCError({
- code: 'INTERNAL_SERVER_ERROR',
- message: 'An unexpected error occurred, please try again later.',
- cause: error
- });
- }
- })
-});
diff --git a/apps/server/src/router/trpc.ts b/apps/server/src/router/trpc.ts
deleted file mode 100644
index 5b71870bc..000000000
--- a/apps/server/src/router/trpc.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { initTRPC } from '@trpc/server';
-import superjson from 'superjson';
-import { Context } from './context';
-
-const t = initTRPC.context().create({
- transformer: superjson,
- errorFormatter({ shape }) {
- return shape;
- },
-});
-
-export const router = t.router;
-export const publicProcedure = t.procedure;
diff --git a/apps/server/src/server.ts b/apps/server/src/server.ts
index 02a80dba8..9a8748fe3 100644
--- a/apps/server/src/server.ts
+++ b/apps/server/src/server.ts
@@ -1,10 +1,11 @@
import { fastifyTRPCPlugin } from '@trpc/server/adapters/fastify';
import fastify from 'fastify';
-import { appRouter } from './router';
-import { createContext } from './router/context';
+import { appRouter } from './trpc';
+import { createContext } from './trpc/context';
import cors from '@fastify/cors';
import * as path from 'node:path';
import serve from '@fastify/static';
+import autoLoad from '@fastify/autoload';
// import { prisma } from './prisma';
const isDev = process.env['NODE_ENV'] === 'development';
@@ -23,7 +24,16 @@ export function createServer(opts: ServerOptions) {
server.register(cors);
server.register(fastifyTRPCPlugin, {
prefix,
- trpcOptions: { router: appRouter, createContext }
+ trpcOptions: {
+ router: appRouter,
+ createContext,
+ onError({ error, type, path, input, ctx, req }) {
+ console.error('Error:', error);
+ if (error.code === 'INTERNAL_SERVER_ERROR') {
+ // send to bug reporting
+ }
+ }
+ }
});
// Serve static files in production. Static files are generated by `yarn build` in the client folder by SvelteKit.
if (!isDev) {
@@ -40,14 +50,16 @@ export function createServer(opts: ServerOptions) {
return reply.status(200).sendFile('index.html');
});
}
- server.get('/api', async () => {
- return { status: 'ok' };
+ server.register(autoLoad, {
+ dir: path.join(__dirname, 'api'),
+ options: { prefix: '/api' }
});
+
const stop = () => server.close();
const start = async () => {
try {
await server.listen({ host: '0.0.0.0', port });
- console.log('Server is listening on port', port);
+ console.log('Coolify server is listening on port', port, 'at 0.0.0.0 🚀');
} catch (err) {
server.log.error(err);
process.exit(1);
diff --git a/apps/server/src/router/context.ts b/apps/server/src/trpc/context.ts
similarity index 56%
rename from apps/server/src/router/context.ts
rename to apps/server/src/trpc/context.ts
index bba7c2749..8c7631f8d 100644
--- a/apps/server/src/router/context.ts
+++ b/apps/server/src/trpc/context.ts
@@ -3,17 +3,20 @@ import { CreateFastifyContextOptions } from '@trpc/server/adapters/fastify';
import jwt from 'jsonwebtoken';
import { env } from '../env';
export interface User {
- name: string | string[];
+ userId: string;
+ teamId: string;
+ permission: string;
+ isAdmin: boolean;
+ iat: number;
}
-export function createContext({ req, res }: CreateFastifyContextOptions) {
+export function createContext({ req }: CreateFastifyContextOptions) {
const token = req.headers.authorization;
+ let user: User | null = null;
if (token) {
- const user = jwt.verify(token, env.COOLIFY_SECRET_KEY);
-
- console.log(user);
+ user = jwt.verify(token, env.COOLIFY_SECRET_KEY) as User;
}
- return { req, res };
+ return { user };
}
export type Context = inferAsyncReturnType;
diff --git a/apps/server/src/trpc/index.ts b/apps/server/src/trpc/index.ts
new file mode 100644
index 000000000..4eddbb785
--- /dev/null
+++ b/apps/server/src/trpc/index.ts
@@ -0,0 +1,21 @@
+import { router } from './trpc';
+import type { Permission } from '@prisma/client';
+
+import {
+ settingsRouter,
+ authRouter,
+ dashboardRouter,
+ applicationsRouter,
+ servicesRouter
+} from './routers';
+
+export const appRouter = router({
+ settings: settingsRouter,
+ auth: authRouter,
+ dashboard: dashboardRouter,
+ applications: applicationsRouter,
+ services: servicesRouter
+});
+
+export type AppRouter = typeof appRouter;
+export type PrismaPermission = Permission;
diff --git a/apps/server/src/trpc/routers/applications.ts b/apps/server/src/trpc/routers/applications.ts
new file mode 100644
index 000000000..3a37d70e8
--- /dev/null
+++ b/apps/server/src/trpc/routers/applications.ts
@@ -0,0 +1,525 @@
+import { z } from 'zod';
+import { privateProcedure, router } from '../trpc';
+import { decrypt, isARM, listSettings } from '../../lib/common';
+import { prisma } from '../../prisma';
+import { executeCommand } from '../../lib/executeCommand';
+import { checkContainer } from '../../lib/docker';
+
+export const applicationsRouter = router({
+ status: privateProcedure
+ .input(
+ z.object({
+ id: z.string()
+ })
+ )
+ .query(async ({ ctx, input }) => {
+ const id = input.id;
+ const teamId = ctx.user?.teamId;
+ if (!teamId) {
+ throw { status: 400, message: 'Team not found.' };
+ }
+ let payload = [];
+ const application: any = await getApplicationFromDB(id, teamId);
+ if (application?.destinationDockerId) {
+ if (application.buildPack === 'compose') {
+ const { stdout: containers } = await executeCommand({
+ dockerId: application.destinationDocker.id,
+ command: `docker ps -a --filter "label=coolify.applicationId=${id}" --format '{{json .}}'`
+ });
+ const containersArray = containers.trim().split('\n');
+ if (containersArray.length > 0 && containersArray[0] !== '') {
+ for (const container of containersArray) {
+ let isRunning = false;
+ let isExited = false;
+ let isRestarting = false;
+ const containerObj = JSON.parse(container);
+ const status = containerObj.State;
+ if (status === 'running') {
+ isRunning = true;
+ }
+ if (status === 'exited') {
+ isExited = true;
+ }
+ if (status === 'restarting') {
+ isRestarting = true;
+ }
+ payload.push({
+ name: containerObj.Names,
+ status: {
+ isRunning,
+ isExited,
+ isRestarting
+ }
+ });
+ }
+ }
+ } else {
+ let isRunning = false;
+ let isExited = false;
+ let isRestarting = false;
+ const status = await checkContainer({
+ dockerId: application.destinationDocker.id,
+ container: id
+ });
+ if (status?.found) {
+ isRunning = status.status.isRunning;
+ isExited = status.status.isExited;
+ isRestarting = status.status.isRestarting;
+ payload.push({
+ name: id,
+ status: {
+ isRunning,
+ isExited,
+ isRestarting
+ }
+ });
+ }
+ }
+ }
+ return payload;
+ })
+});
+
+export async function getApplicationFromDB(id: string, teamId: string) {
+ let application = await prisma.application.findFirst({
+ where: { id, teams: { some: { id: teamId === '0' ? undefined : teamId } } },
+ include: {
+ destinationDocker: true,
+ settings: true,
+ gitSource: { include: { githubApp: true, gitlabApp: true } },
+ secrets: true,
+ persistentStorage: true,
+ connectedDatabase: true,
+ previewApplication: true,
+ dockerRegistry: true
+ }
+ });
+ if (!application) {
+ throw { status: 404, message: 'Application not found.' };
+ }
+ application = decryptApplication(application);
+ const buildPack = application?.buildPack || null;
+ const { baseImage, baseBuildImage, baseBuildImages, baseImages } = setDefaultBaseImage(buildPack);
+
+ // Set default build images
+ if (application && !application.baseImage) {
+ application.baseImage = baseImage;
+ }
+ if (application && !application.baseBuildImage) {
+ application.baseBuildImage = baseBuildImage;
+ }
+ return { ...application, baseBuildImages, baseImages };
+}
+function decryptApplication(application: any) {
+ if (application) {
+ if (application?.gitSource?.githubApp?.clientSecret) {
+ application.gitSource.githubApp.clientSecret =
+ decrypt(application.gitSource.githubApp.clientSecret) || null;
+ }
+ if (application?.gitSource?.githubApp?.webhookSecret) {
+ application.gitSource.githubApp.webhookSecret =
+ decrypt(application.gitSource.githubApp.webhookSecret) || null;
+ }
+ if (application?.gitSource?.githubApp?.privateKey) {
+ application.gitSource.githubApp.privateKey =
+ decrypt(application.gitSource.githubApp.privateKey) || null;
+ }
+ if (application?.gitSource?.gitlabApp?.appSecret) {
+ application.gitSource.gitlabApp.appSecret =
+ decrypt(application.gitSource.gitlabApp.appSecret) || null;
+ }
+ if (application?.secrets.length > 0) {
+ application.secrets = application.secrets.map((s: any) => {
+ s.value = decrypt(s.value) || null;
+ return s;
+ });
+ }
+
+ return application;
+ }
+}
+
+const staticApps = ['static', 'react', 'vuejs', 'svelte', 'gatsby', 'astro', 'eleventy'];
+const nodeBased = [
+ 'react',
+ 'preact',
+ 'vuejs',
+ 'svelte',
+ 'gatsby',
+ 'astro',
+ 'eleventy',
+ 'node',
+ 'nestjs',
+ 'nuxtjs',
+ 'nextjs'
+];
+export function setDefaultBaseImage(
+ buildPack: string | null,
+ deploymentType: string | null = null
+) {
+ const nodeVersions = [
+ {
+ value: 'node:lts',
+ label: 'node:lts'
+ },
+ {
+ value: 'node:18',
+ label: 'node:18'
+ },
+ {
+ value: 'node:17',
+ label: 'node:17'
+ },
+ {
+ value: 'node:16',
+ label: 'node:16'
+ },
+ {
+ value: 'node:14',
+ label: 'node:14'
+ },
+ {
+ value: 'node:12',
+ label: 'node:12'
+ }
+ ];
+ const staticVersions = [
+ {
+ value: 'webdevops/nginx:alpine',
+ label: 'webdevops/nginx:alpine'
+ },
+ {
+ value: 'webdevops/apache:alpine',
+ label: 'webdevops/apache:alpine'
+ },
+ {
+ value: 'nginx:alpine',
+ label: 'nginx:alpine'
+ },
+ {
+ value: 'httpd:alpine',
+ label: 'httpd:alpine (Apache)'
+ }
+ ];
+ const rustVersions = [
+ {
+ value: 'rust:latest',
+ label: 'rust:latest'
+ },
+ {
+ value: 'rust:1.60',
+ label: 'rust:1.60'
+ },
+ {
+ value: 'rust:1.60-buster',
+ label: 'rust:1.60-buster'
+ },
+ {
+ value: 'rust:1.60-bullseye',
+ label: 'rust:1.60-bullseye'
+ },
+ {
+ value: 'rust:1.60-slim-buster',
+ label: 'rust:1.60-slim-buster'
+ },
+ {
+ value: 'rust:1.60-slim-bullseye',
+ label: 'rust:1.60-slim-bullseye'
+ },
+ {
+ value: 'rust:1.60-alpine3.14',
+ label: 'rust:1.60-alpine3.14'
+ },
+ {
+ value: 'rust:1.60-alpine3.15',
+ label: 'rust:1.60-alpine3.15'
+ }
+ ];
+ const phpVersions = [
+ {
+ value: 'webdevops/php-apache:8.2',
+ label: 'webdevops/php-apache:8.2'
+ },
+ {
+ value: 'webdevops/php-nginx:8.2',
+ label: 'webdevops/php-nginx:8.2'
+ },
+ {
+ value: 'webdevops/php-apache:8.1',
+ label: 'webdevops/php-apache:8.1'
+ },
+ {
+ value: 'webdevops/php-nginx:8.1',
+ label: 'webdevops/php-nginx:8.1'
+ },
+ {
+ value: 'webdevops/php-apache:8.0',
+ label: 'webdevops/php-apache:8.0'
+ },
+ {
+ value: 'webdevops/php-nginx:8.0',
+ label: 'webdevops/php-nginx:8.0'
+ },
+ {
+ value: 'webdevops/php-apache:7.4',
+ label: 'webdevops/php-apache:7.4'
+ },
+ {
+ value: 'webdevops/php-nginx:7.4',
+ label: 'webdevops/php-nginx:7.4'
+ },
+ {
+ value: 'webdevops/php-apache:7.3',
+ label: 'webdevops/php-apache:7.3'
+ },
+ {
+ value: 'webdevops/php-nginx:7.3',
+ label: 'webdevops/php-nginx:7.3'
+ },
+ {
+ value: 'webdevops/php-apache:7.2',
+ label: 'webdevops/php-apache:7.2'
+ },
+ {
+ value: 'webdevops/php-nginx:7.2',
+ label: 'webdevops/php-nginx:7.2'
+ },
+ {
+ value: 'webdevops/php-apache:7.1',
+ label: 'webdevops/php-apache:7.1'
+ },
+ {
+ value: 'webdevops/php-nginx:7.1',
+ label: 'webdevops/php-nginx:7.1'
+ },
+ {
+ value: 'webdevops/php-apache:7.0',
+ label: 'webdevops/php-apache:7.0'
+ },
+ {
+ value: 'webdevops/php-nginx:7.0',
+ label: 'webdevops/php-nginx:7.0'
+ },
+ {
+ value: 'webdevops/php-apache:5.6',
+ label: 'webdevops/php-apache:5.6'
+ },
+ {
+ value: 'webdevops/php-nginx:5.6',
+ label: 'webdevops/php-nginx:5.6'
+ },
+ {
+ value: 'webdevops/php-apache:8.2-alpine',
+ label: 'webdevops/php-apache:8.2-alpine'
+ },
+ {
+ value: 'webdevops/php-nginx:8.2-alpine',
+ label: 'webdevops/php-nginx:8.2-alpine'
+ },
+ {
+ value: 'webdevops/php-apache:8.1-alpine',
+ label: 'webdevops/php-apache:8.1-alpine'
+ },
+ {
+ value: 'webdevops/php-nginx:8.1-alpine',
+ label: 'webdevops/php-nginx:8.1-alpine'
+ },
+ {
+ value: 'webdevops/php-apache:8.0-alpine',
+ label: 'webdevops/php-apache:8.0-alpine'
+ },
+ {
+ value: 'webdevops/php-nginx:8.0-alpine',
+ label: 'webdevops/php-nginx:8.0-alpine'
+ },
+ {
+ value: 'webdevops/php-apache:7.4-alpine',
+ label: 'webdevops/php-apache:7.4-alpine'
+ },
+ {
+ value: 'webdevops/php-nginx:7.4-alpine',
+ label: 'webdevops/php-nginx:7.4-alpine'
+ },
+ {
+ value: 'webdevops/php-apache:7.3-alpine',
+ label: 'webdevops/php-apache:7.3-alpine'
+ },
+ {
+ value: 'webdevops/php-nginx:7.3-alpine',
+ label: 'webdevops/php-nginx:7.3-alpine'
+ },
+ {
+ value: 'webdevops/php-apache:7.2-alpine',
+ label: 'webdevops/php-apache:7.2-alpine'
+ },
+ {
+ value: 'webdevops/php-nginx:7.2-alpine',
+ label: 'webdevops/php-nginx:7.2-alpine'
+ },
+ {
+ value: 'webdevops/php-apache:7.1-alpine',
+ label: 'webdevops/php-apache:7.1-alpine'
+ },
+ {
+ value: 'php:8.1-fpm',
+ label: 'php:8.1-fpm'
+ },
+ {
+ value: 'php:8.0-fpm',
+ label: 'php:8.0-fpm'
+ },
+ {
+ value: 'php:8.1-fpm-alpine',
+ label: 'php:8.1-fpm-alpine'
+ },
+ {
+ value: 'php:8.0-fpm-alpine',
+ label: 'php:8.0-fpm-alpine'
+ }
+ ];
+ const pythonVersions = [
+ {
+ value: 'python:3.10-alpine',
+ label: 'python:3.10-alpine'
+ },
+ {
+ value: 'python:3.10-buster',
+ label: 'python:3.10-buster'
+ },
+ {
+ value: 'python:3.10-bullseye',
+ label: 'python:3.10-bullseye'
+ },
+ {
+ value: 'python:3.10-slim-bullseye',
+ label: 'python:3.10-slim-bullseye'
+ },
+ {
+ value: 'python:3.9-alpine',
+ label: 'python:3.9-alpine'
+ },
+ {
+ value: 'python:3.9-buster',
+ label: 'python:3.9-buster'
+ },
+ {
+ value: 'python:3.9-bullseye',
+ label: 'python:3.9-bullseye'
+ },
+ {
+ value: 'python:3.9-slim-bullseye',
+ label: 'python:3.9-slim-bullseye'
+ },
+ {
+ value: 'python:3.8-alpine',
+ label: 'python:3.8-alpine'
+ },
+ {
+ value: 'python:3.8-buster',
+ label: 'python:3.8-buster'
+ },
+ {
+ value: 'python:3.8-bullseye',
+ label: 'python:3.8-bullseye'
+ },
+ {
+ value: 'python:3.8-slim-bullseye',
+ label: 'python:3.8-slim-bullseye'
+ },
+ {
+ value: 'python:3.7-alpine',
+ label: 'python:3.7-alpine'
+ },
+ {
+ value: 'python:3.7-buster',
+ label: 'python:3.7-buster'
+ },
+ {
+ value: 'python:3.7-bullseye',
+ label: 'python:3.7-bullseye'
+ },
+ {
+ value: 'python:3.7-slim-bullseye',
+ label: 'python:3.7-slim-bullseye'
+ }
+ ];
+ const herokuVersions = [
+ {
+ value: 'heroku/builder:22',
+ label: 'heroku/builder:22'
+ },
+ {
+ value: 'heroku/buildpacks:20',
+ label: 'heroku/buildpacks:20'
+ },
+ {
+ value: 'heroku/builder-classic:22',
+ label: 'heroku/builder-classic:22'
+ }
+ ];
+ let payload: any = {
+ baseImage: null,
+ baseBuildImage: null,
+ baseImages: [],
+ baseBuildImages: []
+ };
+ if (nodeBased.includes(buildPack)) {
+ if (deploymentType === 'static') {
+ payload.baseImage = isARM(process.arch) ? 'nginx:alpine' : 'webdevops/nginx:alpine';
+ payload.baseImages = isARM(process.arch)
+ ? staticVersions.filter((version) => !version.value.includes('webdevops'))
+ : staticVersions;
+ payload.baseBuildImage = 'node:lts';
+ payload.baseBuildImages = nodeVersions;
+ } else {
+ payload.baseImage = 'node:lts';
+ payload.baseImages = nodeVersions;
+ payload.baseBuildImage = 'node:lts';
+ payload.baseBuildImages = nodeVersions;
+ }
+ }
+ if (staticApps.includes(buildPack)) {
+ payload.baseImage = isARM(process.arch) ? 'nginx:alpine' : 'webdevops/nginx:alpine';
+ payload.baseImages = isARM(process.arch)
+ ? staticVersions.filter((version) => !version.value.includes('webdevops'))
+ : staticVersions;
+ payload.baseBuildImage = 'node:lts';
+ payload.baseBuildImages = nodeVersions;
+ }
+ if (buildPack === 'python') {
+ payload.baseImage = 'python:3.10-alpine';
+ payload.baseImages = pythonVersions;
+ }
+ if (buildPack === 'rust') {
+ payload.baseImage = 'rust:latest';
+ payload.baseBuildImage = 'rust:latest';
+ payload.baseImages = rustVersions;
+ payload.baseBuildImages = rustVersions;
+ }
+ if (buildPack === 'deno') {
+ payload.baseImage = 'denoland/deno:latest';
+ }
+ if (buildPack === 'php') {
+ payload.baseImage = isARM(process.arch)
+ ? 'php:8.1-fpm-alpine'
+ : 'webdevops/php-apache:8.2-alpine';
+ payload.baseImages = isARM(process.arch)
+ ? phpVersions.filter((version) => !version.value.includes('webdevops'))
+ : phpVersions;
+ }
+ if (buildPack === 'laravel') {
+ payload.baseImage = isARM(process.arch)
+ ? 'php:8.1-fpm-alpine'
+ : 'webdevops/php-apache:8.2-alpine';
+ payload.baseImages = isARM(process.arch)
+ ? phpVersions.filter((version) => !version.value.includes('webdevops'))
+ : phpVersions;
+ payload.baseBuildImage = 'node:18';
+ payload.baseBuildImages = nodeVersions;
+ }
+ if (buildPack === 'heroku') {
+ payload.baseImage = 'heroku/buildpacks:20';
+ payload.baseImages = herokuVersions;
+ }
+ return payload;
+}
diff --git a/apps/server/src/trpc/routers/auth.ts b/apps/server/src/trpc/routers/auth.ts
new file mode 100644
index 000000000..1c431995c
--- /dev/null
+++ b/apps/server/src/trpc/routers/auth.ts
@@ -0,0 +1,178 @@
+import { z } from 'zod';
+import { publicProcedure, router } from '../trpc';
+import { TRPCError } from '@trpc/server';
+import { comparePassword, hashPassword, listSettings, uniqueName } from '../../lib/common';
+import { env } from '../../env';
+import jsonwebtoken from 'jsonwebtoken';
+import { prisma } from '../../prisma';
+import cuid from 'cuid';
+
+export const authRouter = router({
+ register: publicProcedure
+ .input(
+ z.object({
+ email: z.string(),
+ password: z.string()
+ })
+ )
+ .mutation(async ({ input }) => {
+ const { email, password } = input;
+ const userFound = await prisma.user.findUnique({
+ where: { email },
+ include: { teams: true, permission: true }
+ });
+
+ if (userFound) {
+ throw new TRPCError({
+ code: 'BAD_REQUEST',
+ message: 'User already exists.'
+ });
+ }
+ const settings = await listSettings();
+ if (!settings?.isRegistrationEnabled) {
+ throw new TRPCError({
+ code: 'FORBIDDEN',
+ message: 'Registration is disabled.'
+ });
+ }
+ const usersCount = await prisma.user.count();
+ const uid = usersCount === 0 ? '0' : cuid();
+ const permission = 'owner';
+ const isAdmin = true;
+ const hashedPassword = await hashPassword(password);
+
+ // Create the first user as the owner
+ if (usersCount === 0) {
+ await prisma.user.create({
+ data: {
+ id: uid,
+ email,
+ password: hashedPassword,
+ type: 'email',
+ teams: {
+ create: {
+ id: uid,
+ name: uniqueName(),
+ destinationDocker: { connect: { network: 'coolify' } }
+ }
+ },
+ permission: { create: { teamId: uid, permission } }
+ },
+ include: { teams: true }
+ });
+ await prisma.setting.update({
+ where: { id: '0' },
+ data: { isRegistrationEnabled: false }
+ });
+ } else {
+ // Create a new user and team
+ await prisma.user.create({
+ data: {
+ id: uid,
+ email,
+ password: hashedPassword,
+ type: 'email',
+ teams: {
+ create: {
+ id: uid,
+ name: uniqueName()
+ }
+ },
+ permission: { create: { teamId: uid, permission } }
+ },
+ include: { teams: true }
+ });
+ }
+ const payload = {
+ userId: uid,
+ teamId: uid,
+ permission,
+ isAdmin
+ };
+ return {
+ ...payload,
+ token: jsonwebtoken.sign(payload, env.COOLIFY_SECRET_KEY)
+ };
+ }),
+ login: publicProcedure
+ .input(
+ z.object({
+ email: z.string(),
+ password: z.string()
+ })
+ )
+ .mutation(async ({ input }) => {
+ const { email, password } = input;
+ const userFound = await prisma.user.findUnique({
+ where: { email },
+ include: { teams: true, permission: true }
+ });
+
+ if (!userFound) {
+ throw new TRPCError({
+ code: 'BAD_REQUEST',
+ message: 'User already exists.'
+ });
+ }
+ if (userFound.type === 'email') {
+ if (userFound.password === 'RESETME') {
+ const hashedPassword = await hashPassword(password);
+ if (userFound.updatedAt < new Date(Date.now() - 1000 * 60 * 10)) {
+ if (userFound.id === '0') {
+ await prisma.user.update({
+ where: { email: userFound.email },
+ data: { password: 'RESETME' }
+ });
+ } else {
+ await prisma.user.update({
+ where: { email: userFound.email },
+ data: { password: 'RESETTIMEOUT' }
+ });
+ }
+ } else {
+ await prisma.user.update({
+ where: { email: userFound.email },
+ data: { password: hashedPassword }
+ });
+ const payload = {
+ userId: userFound.id,
+ teamId: userFound.id,
+ permission: userFound.permission,
+ isAdmin: true
+ };
+ return {
+ ...payload,
+ token: jsonwebtoken.sign(payload, env.COOLIFY_SECRET_KEY)
+ };
+ }
+ }
+ if (!userFound.password) {
+ throw new TRPCError({
+ code: 'BAD_REQUEST',
+ message: 'Something went wrong. Please try again later.'
+ });
+ }
+ const passwordMatch = comparePassword(password, userFound.password);
+ if (!passwordMatch) {
+ throw new TRPCError({
+ code: 'BAD_REQUEST',
+ message: 'Incorrect password.'
+ });
+ }
+ const payload = {
+ userId: userFound.id,
+ teamId: userFound.id,
+ permission: userFound.permission,
+ isAdmin: true
+ };
+ return {
+ ...payload,
+ token: jsonwebtoken.sign(payload, env.COOLIFY_SECRET_KEY)
+ };
+ }
+ throw new TRPCError({
+ code: 'BAD_REQUEST',
+ message: 'Not implemented yet.'
+ });
+ })
+});
diff --git a/apps/server/src/trpc/routers/dashboard.ts b/apps/server/src/trpc/routers/dashboard.ts
new file mode 100644
index 000000000..273018dc1
--- /dev/null
+++ b/apps/server/src/trpc/routers/dashboard.ts
@@ -0,0 +1,65 @@
+import { privateProcedure, router } from '../trpc';
+import { listSettings } from '../../lib/common';
+import { prisma } from '../../prisma';
+
+export const dashboardRouter = router({
+ resources: privateProcedure.query(async ({ ctx }) => {
+ const id = ctx.user?.teamId === '0' ? undefined : ctx.user?.teamId;
+ let applications = await prisma.application.findMany({
+ where: { teams: { some: { id } } },
+ include: { settings: true, destinationDocker: true, teams: true }
+ });
+ const databases = await prisma.database.findMany({
+ where: { teams: { some: { id } } },
+ include: { settings: true, destinationDocker: true, teams: true }
+ });
+ const services = await prisma.service.findMany({
+ where: { teams: { some: { id } } },
+ include: { destinationDocker: true, teams: true }
+ });
+ const gitSources = await prisma.gitSource.findMany({
+ where: {
+ OR: [{ teams: { some: { id } } }, { isSystemWide: true }]
+ },
+ include: { teams: true }
+ });
+ const destinations = await prisma.destinationDocker.findMany({
+ where: { teams: { some: { id } } },
+ include: { teams: true }
+ });
+ const settings = await listSettings();
+ let foundUnconfiguredApplication = false;
+ for (const application of applications) {
+ if (
+ ((!application.buildPack || !application.branch) && !application.simpleDockerfile) ||
+ !application.destinationDockerId ||
+ (!application.settings?.isBot && !application?.fqdn && application.buildPack !== 'compose')
+ ) {
+ foundUnconfiguredApplication = true;
+ }
+ }
+ let foundUnconfiguredService = false;
+ for (const service of services) {
+ if (!service.fqdn) {
+ foundUnconfiguredService = true;
+ }
+ }
+ let foundUnconfiguredDatabase = false;
+ for (const database of databases) {
+ if (!database.version) {
+ foundUnconfiguredDatabase = true;
+ }
+ }
+ return {
+ foundUnconfiguredApplication,
+ foundUnconfiguredDatabase,
+ foundUnconfiguredService,
+ applications,
+ databases,
+ services,
+ gitSources,
+ destinations,
+ settings
+ };
+ })
+});
diff --git a/apps/server/src/trpc/routers/index.ts b/apps/server/src/trpc/routers/index.ts
new file mode 100644
index 000000000..3dea86e15
--- /dev/null
+++ b/apps/server/src/trpc/routers/index.ts
@@ -0,0 +1,5 @@
+export * from './auth';
+export * from './dashboard';
+export * from './settings';
+export * from './applications';
+export * from './services';
diff --git a/apps/server/src/trpc/routers/services.ts b/apps/server/src/trpc/routers/services.ts
new file mode 100644
index 000000000..1e5a805ed
--- /dev/null
+++ b/apps/server/src/trpc/routers/services.ts
@@ -0,0 +1,118 @@
+import { z } from 'zod';
+import { privateProcedure, router } from '../trpc';
+import { decrypt, getTemplates, listSettings } from '../../lib/common';
+import { prisma } from '../../prisma';
+import { executeCommand } from '../../lib/executeCommand';
+import { checkContainer } from '../../lib/docker';
+
+export const servicesRouter = router({
+ status: privateProcedure
+ .input(
+ z.object({
+ id: z.string()
+ })
+ )
+ .query(async ({ ctx, input }) => {
+ const id = input.id;
+ const teamId = ctx.user?.teamId;
+ if (!teamId) {
+ throw { status: 400, message: 'Team not found.' };
+ }
+ const service = await getServiceFromDB({ id, teamId });
+ const { destinationDockerId } = service;
+ let payload = {};
+ if (destinationDockerId) {
+ const { stdout: containers } = await executeCommand({
+ dockerId: service.destinationDocker.id,
+ command: `docker ps -a --filter "label=com.docker.compose.project=${id}" --format '{{json .}}'`
+ });
+ if (containers) {
+ const containersArray = containers.trim().split('\n');
+ if (containersArray.length > 0 && containersArray[0] !== '') {
+ const templates = await getTemplates();
+ let template = templates.find((t) => t.type === service.type);
+ const templateStr = JSON.stringify(template);
+ if (templateStr) {
+ template = JSON.parse(templateStr.replaceAll('$$id', service.id));
+ }
+ for (const container of containersArray) {
+ let isRunning = false;
+ let isExited = false;
+ let isRestarting = false;
+ let isExcluded = false;
+ const containerObj = JSON.parse(container);
+ const exclude = template?.services[containerObj.Names]?.exclude;
+ if (exclude) {
+ payload[containerObj.Names] = {
+ status: {
+ isExcluded: true,
+ isRunning: false,
+ isExited: false,
+ isRestarting: false
+ }
+ };
+ continue;
+ }
+
+ const status = containerObj.State;
+ if (status === 'running') {
+ isRunning = true;
+ }
+ if (status === 'exited') {
+ isExited = true;
+ }
+ if (status === 'restarting') {
+ isRestarting = true;
+ }
+ payload[containerObj.Names] = {
+ status: {
+ isExcluded,
+ isRunning,
+ isExited,
+ isRestarting
+ }
+ };
+ }
+ }
+ }
+ }
+ return payload;
+ })
+});
+
+export async function getServiceFromDB({
+ id,
+ teamId
+}: {
+ id: string;
+ teamId: string;
+}): Promise {
+ const settings = await prisma.setting.findFirst();
+ const body = await prisma.service.findFirst({
+ where: { id, teams: { some: { id: teamId === '0' ? undefined : teamId } } },
+ include: {
+ destinationDocker: true,
+ persistentStorage: true,
+ serviceSecret: true,
+ serviceSetting: true,
+ wordpress: true,
+ plausibleAnalytics: true
+ }
+ });
+ if (!body) {
+ return null;
+ }
+ // body.type = fixType(body.type);
+
+ if (body?.serviceSecret.length > 0) {
+ body.serviceSecret = body.serviceSecret.map((s) => {
+ s.value = decrypt(s.value);
+ return s;
+ });
+ }
+ if (body.wordpress) {
+ body.wordpress.ftpPassword = decrypt(body.wordpress.ftpPassword);
+ }
+
+ return { ...body, settings };
+}
diff --git a/apps/server/src/trpc/routers/settings.ts b/apps/server/src/trpc/routers/settings.ts
new file mode 100644
index 000000000..e06de54a9
--- /dev/null
+++ b/apps/server/src/trpc/routers/settings.ts
@@ -0,0 +1,80 @@
+// import { z } from 'zod';
+import { publicProcedure, privateProcedure, router } from '../trpc';
+import { TRPCError } from '@trpc/server';
+import { getCurrentUser, getTeamInvitation, listSettings, version } from '../../lib/common';
+import { env } from '../../env';
+import type { Permission, TeamInvitation } from '@prisma/client';
+import jsonwebtoken from 'jsonwebtoken';
+
+export const settingsRouter = router({
+ getBaseSettings: publicProcedure.query(async () => {
+ const settings = await listSettings();
+ return {
+ success: true,
+ data: {
+ isRegistrationEnabled: settings?.isRegistrationEnabled
+ }
+ };
+ }),
+ getInstanceSettings: privateProcedure.query(async ({ ctx }) => {
+ try {
+ const settings = await listSettings();
+
+ let isAdmin = false;
+ let permission = null;
+ let token = null;
+ let pendingInvitations: TeamInvitation[] = [];
+
+ if (!settings) {
+ throw new TRPCError({
+ code: 'INTERNAL_SERVER_ERROR',
+ message: 'An unexpected error occurred, please try again later.'
+ });
+ }
+ if (ctx.user) {
+ const currentUser = await getCurrentUser(ctx.user.userId);
+ if (currentUser) {
+ const foundPermission = currentUser.permission.find(
+ (p: Permission) => p.teamId === ctx.user?.teamId
+ )?.permission;
+ if (foundPermission) {
+ permission = foundPermission;
+ isAdmin = foundPermission === 'owner' || foundPermission === 'admin';
+ }
+ const payload = {
+ userId: ctx.user?.userId,
+ teamId: ctx.user?.teamId,
+ permission,
+ isAdmin,
+ iat: Math.floor(Date.now() / 1000)
+ };
+ token = jsonwebtoken.sign(payload, env.COOLIFY_SECRET_KEY);
+ }
+ pendingInvitations = await getTeamInvitation(ctx.user.userId);
+ }
+ return {
+ success: true,
+ data: {
+ token,
+ userId: ctx.user?.userId,
+ teamId: ctx.user?.teamId,
+ permission,
+ isAdmin,
+ ipv4: ctx.user?.teamId ? settings.ipv4 : null,
+ ipv6: ctx.user?.teamId ? settings.ipv6 : null,
+ version,
+ whiteLabeled: env.COOLIFY_WHITE_LABELED === 'true',
+ whiteLabeledIcon: env.COOLIFY_WHITE_LABELED_ICON,
+ isRegistrationEnabled: settings.isRegistrationEnabled,
+ pendingInvitations
+ }
+ };
+ } catch (error) {
+ throw new TRPCError({
+ code: 'INTERNAL_SERVER_ERROR',
+ message: 'An unexpected error occurred, please try again later.',
+ cause: error
+ });
+ }
+ })
+});
diff --git a/apps/server/src/trpc/trpc.ts b/apps/server/src/trpc/trpc.ts
new file mode 100644
index 000000000..503bd522e
--- /dev/null
+++ b/apps/server/src/trpc/trpc.ts
@@ -0,0 +1,33 @@
+import { initTRPC, TRPCError } from '@trpc/server';
+import superjson from 'superjson';
+import type { Context } from './context';
+
+const t = initTRPC.context().create({
+ transformer: superjson,
+ errorFormatter({ shape }) {
+ return shape;
+ }
+});
+const logger = t.middleware(async ({ path, type, next }) => {
+ const start = Date.now();
+ const result = await next();
+ const durationMs = Date.now() - start;
+ result.ok
+ ? console.log('OK request timing:', { path, type, durationMs })
+ : console.log('Non-OK request timing', { path, type, durationMs });
+ return result;
+});
+
+const isAdmin = t.middleware(async ({ ctx, next }) => {
+ if (!ctx.user) {
+ throw new TRPCError({ code: 'UNAUTHORIZED' });
+ }
+ return next({
+ ctx: {
+ user: ctx.user
+ }
+ });
+});
+export const router = t.router;
+export const privateProcedure = t.procedure.use(isAdmin).use(logger);
+export const publicProcedure = t.procedure.use(logger);
diff --git a/apps/server/tags.json b/apps/server/tags.json
new file mode 100644
index 000000000..0d84f6caa
--- /dev/null
+++ b/apps/server/tags.json
@@ -0,0 +1 @@
+[{"name":"appsmith","image":"appsmith/appsmith-ce","tags":["v1.8.8","v1.8.6","v1.8.4","v1.8.2","v1.8.10","v1.8.0","v1.7.8","v1.7.6","v1.7.4","v1.7.2","v1.7.13","v1.7.11","v1.7.1","v1.6.9","v1.6.7","v1.6.5","v1.6.3","v1.6.22","v1.6.20","v1.6.19","v1.6.17","v1.6.15","v1.6.13","v1.6.11","v1.6.1","v1.5.30","v1.5.28","v1.5.26","v1.5.24","v1.5.22"]},{"name":"appwrite","image":"appwrite/appwrite","tags":["1.1.2","1.1.0","1.0.3","1.0.1","1.0.0","0.9.3","0.9.1","0.8.0","0.7.1","0.6.2","0.6.0","0.5.2","0.5.0","0.3.1","0.2.0","0.15.2","0.15.0","0.14.2","0.14.0","0.13.4","0.13.2","0.13.0","0.12.3","0.12.1","0.12.0","0.11.2","0.11.0","0.10.4","0.10.2","0.10.0"]},{"name":"fider","image":"getfider/fider","tags":["stable","master","main","dev","SHA_ee6e83cfaadadaa56ab76e089e01f5631af3506f","SHA_deb4f9b4f561d890d8a80e6872fea9a98a265cc6","SHA_d5cc307909d43447200483d76b5db74d8ed8349e","SHA_d1674476577a7fd3c88fc29f91c3f35f5bd6a260","SHA_d107cbb157abca6576110080736213efe0955cff","SHA_c9c55b2f5b33a76015241b97e03cfac1254b42a7","SHA_bcf451a3cb02d5c8a489fd30309249296057b084","SHA_bbfe419639514f949a042807addf0fde7d4de225","SHA_adc3afc4c7bcf96931a5f90cab65c282d860dbfd","SHA_ab5283ae95334f10b5041402dce79e333c472015","SHA_a3f4cb5ed0a4ee2d726705fc426636364aac17a1","SHA_a18224142bf51bc6463c3d22f45f62287902e9a6","SHA_8e5cff30d95963eaee2587488d351e0d658c8195","SHA_8cabe2817ce7ccaf2f0a9fdbb1b5d3411de87f81","SHA_7851f9da566132d87fa2a63004e78c3bc9c09c6c","SHA_6c0f2bed1754e9d579eb9575129a6e3dbc529c32","SHA_603508c8790d6a6fb1e852df1a58ead8e5b3ea6c","SHA_55efacf164a4749b50ee68ae8925e7dc9dfa3a0c","SHA_4bdd291ce61e5f5dfc063fa1b2d9be8c9ff1d4c4","SHA_3fba9cb6a9ceab0c78c6cff3220610f591f657cb","SHA_3d635b57606a9885babe91fe975b11429e0f2c38","SHA_3b794edbd9789a8aa38ecd3714bc536a675d3058","SHA_3570c454ad3252b690608f7bf8051737d8519f8a","SHA_263e2709fd145f3ea511e5557e170102899995b0","SHA_255c30ed012fc4c39ffc97efc1d3b00425b17c72","SHA_17f92b16ef790003338f0926fc8d791a9a61333c"]},{"name":"ghost-mariadb","image":"bitnami/ghost","tags":["5.7.1","5.7.0","5.5.0","5.4.1","5.4.0","5.3.1","5.3.0","5.24.2","5.24.1","5.24.0","5.23.0","5.22.9","5.22.8","5.22.7","5.22.6","5.22.5","5.22.4","5.22.3","5.22.2","5.22.11","5.22.10","5.22.1","5.22.0","5.21.0","5.20.0","5.2.4","5.2.3","5.2.2","5.2.1","5.19.3","4.48.8"]},{"name":"ghost-mysql","image":"library/ghost","tags":["5.9.4","5.8.3","5.8.2","5.7.1","5.7.0","5.5.0","5.4.1","5.3.1","5.3.0","5.24.2","5.24.1","5.23.0","5.22.9","5.22.8","5.22.4","5.22.11","5.22.10","5.22.1","5.20.0","5.2.4","5.2.3","5.2.2","5.2.1","5.19.3","5.19.0","5.18.0","5.17.2","5.17.1","5.17.0","5.16.2"]},{"name":"ghost-only","image":"library/ghost","tags":["5.9.4","5.8.3","5.8.2","5.7.1","5.7.0","5.5.0","5.4.1","5.3.1","5.3.0","5.24.2","5.24.1","5.23.0","5.22.9","5.22.8","5.22.4","5.22.11","5.22.10","5.22.1","5.20.0","5.2.4","5.2.3","5.2.2","5.2.1","5.19.3","5.19.0","5.18.0","5.17.2","5.17.1","5.17.0","5.16.2"]},{"name":"gitea","image":"gitea/gitea","tags":["1.9.6","1.9.5","1.9.4","1.9.3","1.9.2","1.9.0","1.8.3","1.8.1","1.8.0","1.7.5","1.7.3","1.7.1","1.7.0","1.6.3","1.6.1","1.6.0","1.5.3","1.5.1","1.5.0","1.4.3","1.4.1","1.4.0","1.3.3","1.3.1","1.3.0","1.2.3","1.2.1","1.2.0","1.17.3","1.17.2"]},{"name":"glitchtip","image":"glitchtip/glitchtip","tags":["v2.0.7","v2.0.5","v2.0.2","v2.0.0","v1.9.2","v1.9.0","v1.8.4","v1.8.2","v1.8.0","v1.7.1","v1.6.4","v1.6.2","v1.6.0","v1.5.3","v1.5.1","v1.4.1","v1.3.3","v1.3.1","v1.2.6","v1.2.4","v1.2.2","v1.2.0","v1.12.4","v1.12.2","v1.12.0","v1.10.3","v1.10.1","v1.1.2","v1.1.0","v1.0.8"]},{"name":"grafana","image":"grafana/grafana","tags":["9.3.1","9.3.0","9.2.7","9.2.6","9.2.5","9.2.4","9.2.3","9.2.2","9.2.1","9.2.0","9.1.8","9.1.7","9.1.6","9.1.5","9.1.4","9.1.3","9.1.2","9.1.1","9.1.0","9.0.9","9.0.8","9.0.7","9.0.6","9.0.5","9.0.4","9.0.3","9.0.2","9.0.1","9.0.0","8.5.9"]},{"name":"hasura","image":"hasura/graphql-engine","tags":["v2.9.0","v2.8.4","v2.8.3","v2.8.2","v2.8.1","v2.8.0","v2.7.0","v2.6.2","v2.6.1","v2.6.0","v2.5.2","v2.5.1","v2.5.0","v2.4.0","v2.3.1","v2.3.0","v2.2.2","v2.2.1","v2.2.0","v2.15.2","v2.15.1","v2.15.0","v2.14.1","v2.14.0","v2.13.2","v2.13.1","v2.13.0","v2.12.1","v2.12.0","v2.11.3"]},{"name":"keycloak","image":"quay.io/keycloak/keycloak","tags":["9.0.3","9.0.0","8.0.1","7.0.0","6.0.1","6.0.0","20.0.1","20.0.0","19.0.3","19.0.1","19.0.0","18.0.1","18.0.0","17.0.1","17.0.0","16.1.0","15.1.1","15.0.2","15.0.0","13.0.1","12.0.4","12.0.2","12.0.0","11.0.2","11.0.0","10.0.1"]},{"name":"languagetool","image":"silviof/docker-languagetool","tags":["latest","5.8","5.7","5.6","5.5","5.4","5.3"]},{"name":"lavalink","image":"fredboat/lavalink","tags":["v3.7","v3.6","v3-vda0b3a4b3916a7b1a2b79702de1143c3a6939810-SNAPSHOT","v3-vc92690c425390bd20f6c51643c67ba79ab85b7e0-SNAPSHOT","v3-vab81dcd46adf3e8a961dd57eacd2a1bde1233e6c-SNAPSHOT","v3-v9c9432704d6a4badfcbd06a57597c54bed8f4326-SNAPSHOT","v3-v3.0","v3-v3","v3-v124f8fae7dab299f9cdf1cb4c1715be455497286-SNAPSHOT","v3-","v3","v2.0.1","v2.0","v2","update-udpqueue-vb4a439d6147dbd8641ea4f265e8efc9f1e16e2d3-SNAPSHOT","update-udpqueue-","update-udpqueue","revert-713-fix-error-for-loading-jda-nas","refactor-github-actions","patch-update-github-actions","patch-more-configurable-github-actions","patch-lavaplayer-update","patch-lavaplayer-bump","patch-build-number","next-api-vd4db194cac7a839a3899857f1f6d7b910369309d-SNAPSHOT","next-api-vc2e018d5ffef54b2d17244b3d213e31723a084d6-SNAPSHOT","next-api-v42cb5f7c58e98d1911e87bffb35aee0a235b85f8-SNAPSHOT","next-api-v31a243bda80badbd7d643f68fc1f87e99639060f-SNAPSHOT","next-api-v17f6884434c2d70d1704b2322a951d9f07af8865-SNAPSHOT","next-api-"]},{"name":"meilisearch","image":"getmeili/meilisearch","tags":["v0.9.0","v0.8.3","v0.8.1","v0.30.0","v0.29.1","v0.29.0","v0.28.1","v0.28.0","v0.27.1","v0.27.0","v0.26.1","v0.26.0","v0.25.1","v0.25.0","v0.23.1","v0.23.0","v0.21.1","v0.21.0","v0.20.0","v0.19.0","v0.18.1","v0.18.0","v0.17.0","v0.16.0","v0.14.1","v0.14.0","v0.12.0","v0.11.0","v0.10.0","0.14.1"]},{"name":"minio","image":"minio/minio","tags":["RELEASE.2022-11-29T23-40-49Z.fips","RELEASE.2022-11-26T22-43-32Z.fips","RELEASE.2022-11-17T23-20-09Z.fips","RELEASE.2022-11-11T03-44-20Z.fips","RELEASE.2022-11-10T18-20-21Z.fips","RELEASE.2022-11-08T05-27-07Z.fips","RELEASE.2022-10-29T06-21-33Z.fips","RELEASE.2022-10-24T18-35-07Z.hotfix.ce525fdaf","RELEASE.2022-10-24T18-35-07Z.fips","RELEASE.2022-10-21T22-37-48Z.fips","RELEASE.2022-10-20T00-55-09Z.fips","RELEASE.2022-10-15T19-57-03Z.fips","RELEASE.2022-10-08T20-11-00Z.fips","RELEASE.2022-10-05T14-58-27Z.fips","RELEASE.2022-10-02T19-29-29Z.fips","RELEASE.2022-09-25T15-44-53Z.fips","RELEASE.2022-09-22T18-57-27Z.fips","RELEASE.2022-09-17T00-09-45Z.hotfix.fc6d6fdbd","RELEASE.2022-09-17T00-09-45Z.hotfix.4bb22d5cd","RELEASE.2022-09-17T00-09-45Z","RELEASE.2022-09-07T22-25-02Z","RELEASE.2022-09-01T23-53-36Z","RELEASE.2022-08-26T19-53-15Z","RELEASE.2022-08-25T07-17-05Z","RELEASE.2022-08-22T23-53-06Z.fips","RELEASE.2022-08-13T21-54-44Z.fips","RELEASE.2022-08-11T04-37-28Z.fips","RELEASE.2022-08-08T18-34-09Z.fips","RELEASE.2022-08-05T23-27-09Z.fips","RELEASE.2022-08-02T23-59-16Z.fips"]},{"name":"n8n","image":"n8nio/n8n","tags":["0.99.1","0.99.0","0.98.0","0.97.0","0.96.0","0.95.1","0.95.0","0.94.1","0.94.0","0.93.0","0.92.0","0.91.0","0.9.0","0.89.2","0.88.1","0.88.0","0.87.2","0.87.1","0.87.0","0.86.1","0.86.0","0.85.0","0.84.4","0.84.3","0.84.1","0.84.0","0.83.0","0.82.1","0.82.0","0.81.0"]},{"name":"nocodb","image":"nocodb/nocodb","tags":["0.99.2","0.99.0","0.98.3","0.98.1","0.97.0","0.96.3","0.96.1","0.92.4","0.92.0","0.91.8","0.91.6","0.91.1","0.90.8","0.90.5","0.90.3","0.90.11","0.90.1","0.9.9","0.9.7","0.9.43","0.9.41","0.9.39","0.9.37","0.9.35","0.9.33","0.9.31","0.9.29","0.9.27","0.9.25","0.9.22"]},{"name":"plausibleanalytics-arm","image":"plausible/analytics","tags":["v1.5.0-rc.2","v1.5.0-rc.1","v1.4.4","v1.4.3","v1.4.2","v1.4.1","v1.4.0.rc.0","v1.4.0-rc.0","v1.4.0","v1.4","v1.3.0-rc.1","v1.3.0-rc.0","v1.3.0","v1.3","v1.2.1","v1.2.0","v1.2-rc.1","v1.2-rc.0","v1.2","v1.1.1","v1.1.0","v1.1","v1.0.0","v1.0","v1","stable","master","loadtest","latest","1.5.0-rc.0"]},{"name":"plausibleanalytics","image":"plausible/analytics","tags":["v1.5.0-rc.2","v1.5.0-rc.1","v1.4.4","v1.4.3","v1.4.2","v1.4.1","v1.4.0.rc.0","v1.4.0-rc.0","v1.4.0","v1.4","v1.3.0-rc.1","v1.3.0-rc.0","v1.3.0","v1.3","v1.2.1","v1.2.0","v1.2-rc.1","v1.2-rc.0","v1.2","v1.1.1","v1.1.0","v1.1","v1.0.0","v1.0","v1","stable","master","loadtest","latest","1.5.0-rc.0"]},{"name":"pocketbase","image":"coollabsio/pocketbase","tags":["0.8.0-arm64","0.8.0-amd64","0.8.0-aarch64","0.8.0"]},{"name":"searxng","image":"searxng/searxng","tags":["2022.12.02-ffb72dfd","2022.12.02-890d63b9","2022.12.02-4970db05","2022.12.02-317fe0a2","2022.11.30-f19837cf","2022.11.30-44d4a171","2022.11.30-0361f836","2022.11.29-a8359dd4","2022.11.29-82af2f44","2022.11.29-768659f2","2022.11.29-5b19f892","2022.11.29-3579a38a","2022.11.29-1b2f1c17","2022.11.25-5ca6868c","2022.11.25-28ae469f","2022.11.25-1314c1c5","2022.11.19-b5371b7a","2022.11.18-fe8b0472","2022.11.18-1cdadf4b","2022.11.11-e6345758","2022.11.11-3a765113","2022.11.10-117f69fa","2022.11.09-ee4475ff","2022.11.07-d3949269","2022.11.07-8f19bdaf","2022.11.06-ae54c7d5","2022.11.06-2dc5c0e1","2022.11.05-e9f42e1c","2022.11.05-d764d94a","2022.11.05-d3a7399e"]},{"name":"trilium","image":"zadam/trilium","tags":["0.57.2","0.56.1","0.55.1","0.54.2","0.53.2","0.52.4","0.52.2","0.51.2","0.50.3","0.50.1","0.49.5","0.49.3","0.48.9","0.48.7","0.48.4","0.48.2","0.47.8","0.47.6","0.47.4","0.47.2","0.46.7","0.46.5","0.45.9","0.45.7","0.45.5","0.45.3","0.45.10","0.44.8","0.44.6","0.44.4"]},{"name":"umami-postgresql","image":"ghcr.io/umami-software/umami","tags":["postgresql-v1.39.5","postgresql-v1.39.4","postgresql-v1.39.3","postgresql-v1.39.2","postgresql-v1.39.1","postgresql-v1.39.0","postgresql-v1.38.0","postgresql-v1.37.0","postgresql-v1.36.1","postgresql-v1.36.0","postgresql-v1.35.0","postgresql-v1.34.0","postgresql-v1.33.3","postgresql-latest","mysql-v1.39.5","mysql-v1.39.4","mysql-v1.39.3","mysql-v1.39.2","mysql-v1.39.1","mysql-v1.39.0","mysql-v1.38.0","mysql-v1.37.0","mysql-v1.36.1","mysql-v1.36.0","mysql-v1.35.0","mysql-v1.34.0","mysql-v1.33.3","mysql-latest"]},{"name":"umami","image":"ghcr.io/umami-software/umami","tags":["postgresql-v1.39.5","postgresql-v1.39.4","postgresql-v1.39.3","postgresql-v1.39.2","postgresql-v1.39.1","postgresql-v1.39.0","postgresql-v1.38.0","postgresql-v1.37.0","postgresql-v1.36.1","postgresql-v1.36.0","postgresql-v1.35.0","postgresql-v1.34.0","postgresql-v1.33.3","postgresql-latest","mysql-v1.39.5","mysql-v1.39.4","mysql-v1.39.3","mysql-v1.39.2","mysql-v1.39.1","mysql-v1.39.0","mysql-v1.38.0","mysql-v1.37.0","mysql-v1.36.1","mysql-v1.36.0","mysql-v1.35.0","mysql-v1.34.0","mysql-v1.33.3","mysql-latest"]},{"name":"uptimekuma","image":"louislam/uptime-kuma","tags":["1.9.2","1.9.1","1.9.0","1.8.0","1.7.3","1.7.1","1.7.0","1.6.3","1.6.2","1.6.1","1.6.0","1.5.3","1.5.2","1.5.0","1.3.1","1.2.0","1.18.5","1.18.4","1.18.3","1.18.2","1.18.1","1.18.0","1.17.1","1.17.0","1.16.1","1.16.0","1.15.1","1.15.0","1.14.1","1.14.0"]},{"name":"vaultwarden","image":"vaultwarden/server","tags":["1.26.0","1.25.2","1.25.1","1.25.0","1.24.0","1.23.1","1.23.0","1.22.2","1.22.1","1.22.0","1.21.0"]},{"name":"vscodeserver","image":"codercom/code-server","tags":["4.8.3","4.8.2","4.8.1","4.8.0","4.7.0","4.6.0","4.5.1","4.4.0","4.2.0","4.0.2","3.9.3","3.9.1","3.8.1","3.7.4","3.7.2","3.7.0","3.6.1","3.5.0","3.4.0","3.3.0","3.2.0","3.11.1","3.10.2","3.10.0","3.1.1","3.1.0","3.0.2","3.0.0"]},{"name":"weblate","image":"weblate/weblate","tags":["latest","edge-2022-12-01-0295bd44d4d9da0e0836b9152319fba173a0825e","edge-2022-11-28-f28431a1e78f88bf49ccf539fbc00afe0925542d","edge-2022-11-26-558811de16025b83de43d2747f1fe209a5b829f1","edge-2022-11-23-4a1fe25c7b70e49156e02183a8deec3b357b9030","edge-2022-11-22-9a178e7f5c2e387329592a1dd7700671f64f6682","edge-2022-11-21-eb741ebad70211ecb1babdfd23e4f43c5a59fc7b","edge-2022-11-21-4580d37f616650cf5b0851fee051651f785e8852","edge-2022-11-21-0f74d6c4d3777dbf28affd09b45c69c85ed01d84","edge-2022-11-15-cad0a043b32c1ee61611ab258db0f01c5e6d718f","edge-2022-11-10-bf41db3afbab22384e103718094738dcfdc1a270","edge-2022-11-09-9bc90ce8b873778d2f486eccd0163bb1bb65ca6e","edge-2022-11-08-36e221037ff7097f8cd2c88d779135b6c7d3f363","edge-2022-11-08-3568e3c6759a9e9b779d98cb98393526d451466a","edge-2022-11-08-261d197970ca0679514d32ff783467972e807061","edge-2022-11-05-fa5cb203d854a11cc7850868a2890168afa3e7da","edge-2022-11-05-d93ae789eef8f065240f9fb6feb3edb236a7e6f8","edge-2022-11-05-8fc2be8e9d22e5ca2da2773488da7f72c5927ec3","edge-2022-11-05-85da67e88a113bed65530f0695ad4cddec0ed05a","edge-2022-11-05-3f4d77b6f2cb16bf008a4ef587e843ccb9c0c5d0","edge-2022-11-05-226eed520a2b32c3583c6e3247109ec8950764e7","edge-2022-11-03-487f3255cb89415fbe0769fa4b7bd2a9209deca6","edge-2022-11-02-e4171e0c5657ca38341cce8ac31f5cbdf25389eb","edge-2022-11-02-6d886c40cd62eb23d21f7c0a1840b4a7a4c51ad0","edge-2022-11-01-608df4dd95a2d1f76c15cddd9e116bb4c3229168","edge-2022-11-01-54957be78eb76f602ceae50c0b01b64b20402b2a","edge-2022-10-31-c55c7302a6c82a160ee9d711893c12d67ecd3b27","edge-2022-10-26-c69cfdd83ed1fad4a4d57398552b8c70894a6586","edge-2022-10-26-410b3aff37de5bbfacbc47642ce28b2518bee506","edge-2022-10-25-e09e2c29ed3748eb0fa248453635dd27768e8dd9"]},{"name":"wordpress-only","image":"library/wordpress","tags":["php8.1-fpm-alpine","php8.1-fpm","php8.1-apache","php8.1","php8.0-fpm-alpine","php8.0-fpm","php8.0-apache","php8.0","php7.4-fpm-alpine","php7.4-fpm","php7.4-apache","php7.4","php7.3-fpm-alpine","php7.3-fpm","php7.3-apache","php7.3","php7.2-fpm-alpine","php7.2-fpm","php7.2-apache","php7.2","php7.1-fpm-alpine","php7.1-fpm","php7.1-apache","php7.1","php7.0-fpm-alpine","php7.0-fpm","php7.0-apache","php7.0","php5.6-fpm-alpine","php5.6-fpm"]},{"name":"wordpress","image":"library/wordpress","tags":["php8.1-fpm-alpine","php8.1-fpm","php8.1-apache","php8.1","php8.0-fpm-alpine","php8.0-fpm","php8.0-apache","php8.0","php7.4-fpm-alpine","php7.4-fpm","php7.4-apache","php7.4","php7.3-fpm-alpine","php7.3-fpm","php7.3-apache","php7.3","php7.2-fpm-alpine","php7.2-fpm","php7.2-apache","php7.2","php7.1-fpm-alpine","php7.1-fpm","php7.1-apache","php7.1","php7.0-fpm-alpine","php7.0-fpm","php7.0-apache","php7.0","php5.6-fpm-alpine","php5.6-fpm"]}]
\ No newline at end of file
diff --git a/apps/server/templates.json b/apps/server/templates.json
new file mode 100644
index 000000000..256cca609
--- /dev/null
+++ b/apps/server/templates.json
@@ -0,0 +1 @@
+[{"templateVersion":"1.0.0","defaultVersion":"0.8.0","documentation":"https://pocketbase.io/docs/","type":"pocketbase","name":"Pocketbase","description":"Open Source realtime backend in 1 file","services":{"$$id":{"image":"coollabsio/pocketbase:$$core_version","volumes":["$$id-data:/app/pb_data"],"ports":["8080"]}}},{"templateVersion":"1.0.0","defaultVersion":"1.5.0-rc.0","documentation":"https://plausible.io/doc/","type":"plausibleanalytics-arm","name":"Plausible Analytics (ARM)","description":"A lightweight and open-source website analytics tool.","labels":["analytics","statistics","plausible","gdpr","no-cookie","google analytics"],"services":{"$$id":{"name":"Plausible Analytics","command":"sh -c \"sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh db init-admin && /entrypoint.sh run\"","depends_on":["$$id-postgresql","$$id-clickhouse"],"image":"plausible/analytics:$$core_version","environment":["ADMIN_USER_EMAIL=$$config_admin_user_email","ADMIN_USER_NAME=$$config_admin_user_name","ADMIN_USER_PWD=$$secret_admin_user_pwd","BASE_URL=$$config_base_url","SECRET_KEY_BASE=$$secret_secret_key_base","DISABLE_AUTH=$$config_disable_auth","DISABLE_REGISTRATION=$$config_disable_registration","DATABASE_URL=$$secret_database_url","CLICKHOUSE_DATABASE_URL=$$secret_clickhouse_database_url"],"ports":["8000"]},"$$id-postgresql":{"name":"PostgreSQL","image":"postgres:14-alpine","volumes":["$$id-postgresql-data:/var/lib/postgresql/data"],"environment":["POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_USER=$$config_postgres_user","POSTGRES_DB=$$config_postgres_db"]},"$$id-clickhouse":{"name":"Clickhouse","volumes":["$$id-clickhouse-data:/var/lib/clickhouse"],"image":"clickhouse/clickhouse-server:22.6-alpine","ulimits":{"nofile":{"soft":262144,"hard":262144}},"files":[{"location":"/etc/clickhouse-server/users.d/logging.xml","content":"warningtrue"},{"location":"/etc/clickhouse-server/config.d/logging.xml","content":"00"},{"location":"/docker-entrypoint-initdb.d/init.query","content":"CREATE DATABASE IF NOT EXISTS plausible;"},{"location":"/docker-entrypoint-initdb.d/init-db.sh","content":"clickhouse client --queries-file /docker-entrypoint-initdb.d/init.query"}]}},"variables":[{"id":"$$config_base_url","name":"BASE_URL","label":"Base URL","defaultValue":"$$generate_fqdn","description":"You must set this to the FQDN of the Plausible Analytics instance. This is used to generate the links to the Plausible Analytics instance."},{"id":"$$secret_database_url","name":"DATABASE_URL","label":"Database URL for PostgreSQL","defaultValue":"postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db","description":""},{"id":"$$secret_clickhouse_database_url","name":"CLICKHOUSE_DATABASE_URL","label":"Database URL for Clickhouse","defaultValue":"http://$$id-clickhouse:8123/plausible","description":""},{"id":"$$config_admin_user_email","name":"ADMIN_USER_EMAIL","label":"Admin Email Address","defaultValue":"admin@example.com","description":"This is the admin email. Please change it."},{"id":"$$config_admin_user_name","name":"ADMIN_USER_NAME","label":"Admin User Name","defaultValue":"$$generate_username","description":"This is the admin username. Please change it."},{"id":"$$secret_admin_user_pwd","name":"ADMIN_USER_PWD","label":"Admin User Password","defaultValue":"$$generate_password","description":"This is the admin password. Please change it.","showOnConfiguration":true},{"id":"$$secret_secret_key_base","name":"SECRET_KEY_BASE","label":"Secret Key Base","defaultValue":"$$generate_hex(64)","description":""},{"id":"$$config_disable_auth","name":"DISABLE_AUTH","label":"Disable Authentication","defaultValue":"false","description":""},{"id":"$$config_disable_registration","name":"DISABLE_REGISTRATION","label":"Disable Registration","defaultValue":"true","description":""},{"id":"$$config_postgres_user","main":"$$id-postgresql","name":"POSTGRES_USER","label":"PostgreSQL Username","defaultValue":"postgresql","description":""},{"id":"$$secret_postgres_password","main":"$$id-postgresql","name":"POSTGRES_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_postgres_db","main":"$$id-postgresql","name":"POSTGRES_DB","label":"PostgreSQL Database","defaultValue":"plausible","description":""},{"id":"$$config_scriptName","name":"SCRIPT_NAME","label":"Custom Script Name","defaultValue":"plausible.js","description":"This is the default script name."}]},{"templateVersion":"1.0.0","defaultVersion":"1.17","documentation":"https://docs.gitea.io","type":"gitea","name":"Gitea","description":"Gitea is a community managed lightweight code hosting solution written in Go.","labels":["storage","git"],"services":{"$$id":{"name":"Gitea","documentation":"https://docs.gitea.io","image":"gitea/gitea:$$core_version","volumes":["$$id-data:/data","/etc/timezone:/etc/timezone:ro","/etc/localtime:/etc/localtime:ro"],"environment":["USER_UID=1000","USER_GID=1000","DOMAIN=$$config_domain","SSH_DOMAIN=$$config_ssh_domain","ROOT_URL=$$config_root_url","SECRET_KEY=$$secret_secret_key","INTERNAL_TOKEN=$$secret_internal_token","SSH_PORT=22","START_SSH_SERVER=$$config_start_ssh_server"],"ports":["3000","22"],"proxy":[{"port":"22","hostPort":"$$config_hostport_ssh"}]}},"variables":[{"id":"$$config_hostport_ssh","name":"SSH_PORT","label":"SSH Port","defaultValue":"8022","description":"","required":true},{"id":"$$config_domain","name":"DOMAIN","label":"Domain","defaultValue":"$$generate_domain","description":""},{"id":"$$config_ssh_domain","name":"SSH_DOMAIN","label":"SSH Domain","defaultValue":"$$generate_domain","description":""},{"id":"$$config_start_ssh_server","name":"START_SSH_SERVER","label":"Start SSH Server","defaultValue":"true","description":""},{"id":"$$config_root_url","name":"ROOT_URL","label":"Root URL of Gitea","defaultValue":"$$generate_fqdn_slash","description":""},{"id":"$$secret_secret_key","name":"SECRET_KEY","label":"Secret Key","defaultValue":"$$generate_hex(32)","description":""},{"id":"$$secret_internal_token","name":"INTERNAL_TOKEN","label":"Internal JWT Token","defaultValue":"$$generate_token","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"20.0","documentation":"https://www.keycloak.org/documentation","type":"keycloak","name":"Keycloak","description":"Keycloak provides user federation, strong authentication, user management, fine-grained authorization, and more.","labels":["authentication","authorization","oidconnect","saml2"],"services":{"$$id":{"name":"Keycloak","command":"start --db=postgres --features=token-exchange --import-realm","depends_on":["$$id-postgresql"],"image":"quay.io/keycloak/keycloak:$$core_version","volumes":["$$id-import:/opt/keycloak/data/import"],"environment":["KC_HEALTH_ENABLED=true","KC_PROXY=edge","KC_DB=postgres","KC_HOSTNAME=$$config_keycloak_domain","KEYCLOAK_ADMIN=$$config_admin_user","KEYCLOAK_ADMIN_PASSWORD=$$secret_keycloak_admin_password","KC_DB_PASSWORD=$$secret_postgres_password","KC_DB_USERNAME=$$config_postgres_user","KC_DB_URL=$$secret_keycloak_database_url"],"ports":["8080"]},"$$id-postgresql":{"name":"PostgreSQL","depends_on":[],"image":"postgres:14-alpine","volumes":["$$id-postgresql-data:/var/lib/postgresql/data"],"environment":["POSTGRES_USER=$$config_postgres_user","POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_DB=$$config_postgres_db"],"ports":[]}},"variables":[{"id":"$$config_keycloak_domain","name":"KEYCLOAK_DOMAIN","label":"Keycloak Domain","defaultValue":"$$generate_domain","description":""},{"id":"$$secret_keycloak_database_url","name":"KEYCLOAK_DATABASE_URL","label":"Keycloak Database Url","defaultValue":"jdbc:postgresql://$$id-postgresql:5432/$$config_postgres_db","description":""},{"id":"$$config_admin_user","name":"KEYCLOAK_ADMIN","label":"Keycloak Admin User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_keycloak_admin_password","name":"KEYCLOAK_ADMIN_PASSWORD","label":"Keycloak Admin Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_postgres_user","main":"$$id-postgresql","name":"POSTGRES_USER","label":"PostgreSQL User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_postgres_password","main":"$$id-postgresql","name":"POSTGRES_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_postgres_db","main":"$$id-postgresql","name":"POSTGRES_DB","label":"PostgreSQL Database","defaultValue":"keycloak","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"v3.6","documentation":"https://github.com/freyacodes/Lavalink","description":"Standalone audio sending node based on Lavaplayer.","type":"lavalink","name":"Lavalink","labels":["discord","discord bot","audio","lavalink","jda"],"services":{"$$id":{"name":"Lavalink","image":"fredboat/lavalink:$$core_version","environment":[],"volumes":["$$id-lavalink:/lavalink"],"ports":["2333"],"files":[{"location":"/opt/Lavalink/application.yml","content":"server:\n port: $$config_port\n address: 0.0.0.0\nlavalink:\n server:\n password: \"$$secret_password\"\n sources:\n youtube: true\n bandcamp: true\n soundcloud: true\n twitch: true\n vimeo: true\n http: true\n local: false\n\nlogging:\n file:\n path: ./logs/\n\n level:\n root: INFO\n lavalink: INFO\n\n logback:\n rollingpolicy:\n max-file-size: 1GB\n max-history: 30"}]}},"variables":[{"id":"$$config_port","name":"PORT","label":"Port","defaultValue":"2333","required":true},{"id":"$$secret_password","name":"PASSWORD","label":"Password","defaultValue":"$$generate_password","required":true}]},{"templateVersion":"1.0.0","defaultVersion":"v1.8.6","documentation":"https://docs.appsmith.com/getting-started/setup/instance-configuration/","type":"appsmith","name":"Appsmith","description":"Fastest way to build internal apps over any database or API.","services":{"$$id":{"image":"appsmith/appsmith-ce:$$core_version","environment":["APPSMITH_MAIL_ENABLED=$$config_appsmith_mail_enabled","APPSMITH_DISABLE_TELEMETRY=$$config_appsmith_disable_telemetry","APPSMITH_DISABLE_INTERCOM=$$config_appsmith_disable_intercom"],"volumes":["$$id-stacks-data:/appsmith-stacks"],"ports":["80"]}},"variables":[{"id":"$$config_appsmith_mail_enabled","name":"APPSMITH_MAIL_ENABLED","label":"Enable Mail","defaultValue":"false","description":""},{"id":"$$config_appsmith_disable_telemetry","name":"APPSMITH_DISABLE_TELEMETRY","label":"Disable Telemetry","defaultValue":"true","description":""},{"id":"$$config_appsmith_disable_intercom","name":"APPSMITH_DISABLE_INTERCOM","label":"Disable Intercom","defaultValue":"true","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"0.56.2","documentation":"https://hub.docker.com/r/zadam/trilium","description":"A hierarchical note taking application with focus on building large personal knowledge bases.","labels":["personal","knowledge","notes","wiki"],"type":"trilium","name":"Trilium Notes","services":{"$$id":{"image":"zadam/trilium:$$core_version","environment":[],"volumes":["$$id-trilium:/home/node/trilium-data"],"ports":["8080"]}},"variables":[]},{"templateVersion":"1.0.0","defaultVersion":"1.9.2","documentation":"https://hub.docker.com/r/louislam/uptime-kuma","description":"A free & fancy self-hosted monitoring tool.","labels":["uptime"],"type":"uptimekuma","name":"UptimeKuma","services":{"$$id":{"image":"louislam/uptime-kuma:$$core_version","environment":[],"volumes":["$$id-uptimekuma:/app/data"],"ports":["3001"]}},"variables":[]},{"templateVersion":"1.0.0","defaultVersion":"5.8","documentation":"https://hub.docker.com/r/silviof/docker-languagetool","description":"A multilingual grammar, style and spell checker.","type":"languagetool","name":"LanguageTool","services":{"$$id":{"image":"silviof/docker-languagetool:$$core_version","environment":[],"volumes":["$$id-ngrams:/ngrams"],"ports":["8010"]}},"variables":[]},{"templateVersion":"1.0.0","defaultVersion":"1.26.0","documentation":"https://hub.docker.com/r/vaultwarden/server","description":"Bitwarden compatible server written in Rust.","type":"vaultwarden","name":"VaultWarden","labels":["bitwarden","password manager"],"services":{"$$id":{"image":"vaultwarden/server:$$core_version","environment":[],"volumes":["$$id-data:/data"],"ports":["80"]}},"variables":[]},{"templateVersion":"1.0.0","defaultVersion":"9.2.3","documentation":"https://hub.docker.com/r/grafana/grafana","type":"grafana","name":"Grafana","description":"Grafana allows you to query, visualize, alert on and understand your metrics.","labels":["monitoring","metrics","dashboard"],"services":{"$$id":{"image":"grafana/grafana:$$core_version","environment":[],"volumes":["$$id-config:/etc/grafana","$$id-grafana:/var/lib/grafana"],"ports":["3000"]}},"variables":[]},{"templateVersion":"1.0.0","defaultVersion":"1.0.3","documentation":"https://appwrite.io/docs","type":"appwrite","name":"Appwrite","description":"Secure Backend Server for Web, Mobile & Flutter Developers.","labels":["serverless","backend","storage","api"],"services":{"$$id":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_WORKER_PER_CORE=$$config__app_worker_per_core","_APP_LOCALE=$$config__app_locale","_APP_CONSOLE_WHITELIST_ROOT=$$config__app_console_whitelist_root","_APP_CONSOLE_WHITELIST_EMAILS=$$config__app_console_whitelist_emails","_APP_CONSOLE_WHITELIST_IPS=$$config__app_console_whitelist_ips","_APP_SYSTEM_EMAIL_NAME=$$config__app_system_email_name","_APP_SYSTEM_EMAIL_ADDRESS=$$config__app_system_email_address","_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=$$config__app_system_security_email_address","_APP_SYSTEM_RESPONSE_FORMAT=$$config__app_system_response_format","_APP_OPTIONS_ABUSE=$$config__app_options_abuse","_APP_OPTIONS_FORCE_HTTPS=$$config__app_options_force_https","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_DOMAIN=$$config__app_domain","_APP_DOMAIN_TARGET=$$config__app_domain_target","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_SMTP_HOST=$$config__app_smtp_host","_APP_SMTP_PORT=$$config__app_smtp_port","_APP_SMTP_SECURE=$$config__app_smtp_secure","_APP_SMTP_USERNAME=$$config__app_smtp_username","_APP_SMTP_PASSWORD=$$secret__app_smtp_password","_APP_USAGE_STATS=$$config__app_usage_stats","_APP_INFLUXDB_HOST=$$config__app_influxdb_host","_APP_INFLUXDB_PORT=$$config__app_influxdb_port","_APP_STORAGE_LIMIT=$$config__app_storage_limit","_APP_STORAGE_PREVIEW_LIMIT=$$config__app_storage_preview_limit","_APP_STORAGE_ANTIVIRUS=$$config__app_storage_antivirus_enabled","_APP_STORAGE_ANTIVIRUS_HOST=$$config__app_storage_antivirus_host","_APP_STORAGE_ANTIVIRUS_PORT=$$config__app_storage_antivirus_port","_APP_STORAGE_DEVICE=$$config__app_storage_device","_APP_STORAGE_S3_ACCESS_KEY=$$secret__app_storage_s3_access_key","_APP_STORAGE_S3_SECRET=$$secret__app_storage_s3_secret","_APP_STORAGE_S3_REGION=$$config__app_storage_s3_region","_APP_STORAGE_S3_BUCKET=$$config__app_storage_s3_bucket","_APP_STORAGE_DO_SPACES_ACCESS_KEY=$$secret__app_storage_do_spaces_access_key","_APP_STORAGE_DO_SPACES_SECRET=$$secret__app_storage_do_spaces_secret","_APP_STORAGE_DO_SPACES_REGION=$$config__app_storage_do_spaces_region","_APP_STORAGE_DO_SPACES_BUCKET=$$config__app_storage_do_spaces_bucket","_APP_STORAGE_BACKBLAZE_ACCESS_KEY=$$secret__app_storage_backblaze_access_key","_APP_STORAGE_BACKBLAZE_SECRET=$$secret__app_storage_backblaze_secret","_APP_STORAGE_BACKBLAZE_REGION=$$config__app_storage_backblaze_region","_APP_STORAGE_BACKBLAZE_BUCKET=$$config__app_storage_backblaze_bucket","_APP_STORAGE_LINODE_ACCESS_KEY=$$secret__app_storage_linode_access_key","_APP_STORAGE_LINODE_SECRET=$$secret__app_storage_linode_secret","_APP_STORAGE_LINODE_REGION=$$config__app_storage_linode_region","_APP_STORAGE_LINODE_BUCKET=$$config__app_storage_linode_bucket","_APP_STORAGE_WASABI_ACCESS_KEY=$$secret__app_storage_wasabi_access_key","_APP_STORAGE_WASABI_SECRET=$$secret__app_storage_wasabi_secret","_APP_STORAGE_WASABI_REGION=$$config__app_storage_wasabi_region","_APP_STORAGE_WASABI_BUCKET=$$config__app_storage_wasabi_bucket","_APP_FUNCTIONS_SIZE_LIMIT=$$config__app_functions_size_limit","_APP_FUNCTIONS_TIMEOUT=$$config__app_functions_timeout","_APP_FUNCTIONS_BUILD_TIMEOUT=$$config__app_functions_build_timeout","_APP_FUNCTIONS_CONTAINERS=$$config__app_functions_containers","_APP_FUNCTIONS_CPUS=$$config__app_functions_cpus","_APP_FUNCTIONS_MEMORY=$$config__app_functions_memory_allocated","_APP_FUNCTIONS_MEMORY_SWAP=$$config__app_functions_memory_swap","_APP_FUNCTIONS_RUNTIMES=$$config__app_functions_runtimes","_APP_EXECUTOR_SECRET=$$secret__app_executor_secret","_APP_EXECUTOR_HOST=$$config__app_executor_host","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","_APP_STATSD_HOST=$$config__app_statsd_host","_APP_STATSD_PORT=$$config__app_statsd_port","_APP_MAINTENANCE_INTERVAL=$$config__app_maintenance_interval","_APP_MAINTENANCE_RETENTION_EXECUTION=$$config__app_maintenance_retention_execution","_APP_MAINTENANCE_RETENTION_CACHE=$$config__app_maintenance_retention_cache","_APP_MAINTENANCE_RETENTION_ABUSE=$$config__app_maintenance_retention_abuse","_APP_MAINTENANCE_RETENTION_AUDIT=$$config__app_maintenance_retention_audit","_APP_SMS_PROVIDER=$$config__app_sms_provider","_APP_SMS_FROM=$$config__app_sms_from","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":["$$id-uploads:/storage/uploads","$$id-cache:/storage/cache","$$id-config:/storage/config","$$id-certificates:/storage/certificates","$$id-functions:/storage/functions"],"ports":["80"],"proxy":[{"port":"80"}]},"$$id-executor":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_FUNCTIONS_TIMEOUT=$$config__app_functions_timeout","_APP_FUNCTIONS_BUILD_TIMEOUT=$$config__app_functions_build_timeout","_APP_FUNCTIONS_CONTAINERS=$$config__app_functions_containers","_APP_FUNCTIONS_RUNTIMES=$$config__app_functions_runtimes","_APP_FUNCTIONS_CPUS=$$config__app_functions_cpus","_APP_FUNCTIONS_MEMORY=$$config__app_functions_memory_allocated","_APP_FUNCTIONS_MEMORY_SWAP=$$config__app_functions_memory_swap","_APP_FUNCTIONS_INACTIVE_THRESHOLD=$$config__app_functions_inactive_threshold","_APP_EXECUTOR_SECRET=$$secret__app_executor_secret","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","_APP_STORAGE_DEVICE=$$config__app_storage_device","_APP_STORAGE_S3_ACCESS_KEY=$$secret__app_storage_s3_access_key","_APP_STORAGE_S3_SECRET=$$secret__app_storage_s3_secret","_APP_STORAGE_S3_REGION=$$config__app_storage_s3_region","_APP_STORAGE_S3_BUCKET=$$config__app_storage_s3_bucket","_APP_STORAGE_DO_SPACES_ACCESS_KEY=$$secret__app_storage_do_spaces_access_key","_APP_STORAGE_DO_SPACES_SECRET=$$secret__app_storage_do_spaces_secret","_APP_STORAGE_DO_SPACES_REGION=$$config__app_storage_do_spaces_region","_APP_STORAGE_DO_SPACES_BUCKET=$$config__app_storage_do_spaces_bucket","_APP_STORAGE_BACKBLAZE_ACCESS_KEY=$$secret__app_storage_backblaze_access_key","_APP_STORAGE_BACKBLAZE_SECRET=$$secret__app_storage_backblaze_secret","_APP_STORAGE_BACKBLAZE_REGION=$$config__app_storage_backblaze_region","_APP_STORAGE_BACKBLAZE_BUCKET=$$config__app_storage_backblaze_bucket","_APP_STORAGE_LINODE_ACCESS_KEY=$$secret__app_storage_linode_access_key","_APP_STORAGE_LINODE_SECRET=$$secret__app_storage_linode_secret","_APP_STORAGE_LINODE_REGION=$$config__app_storage_linode_region","_APP_STORAGE_LINODE_BUCKET=$$config__app_storage_linode_bucket","_APP_STORAGE_WASABI_ACCESS_KEY=$$secret__app_storage_wasabi_access_key","_APP_STORAGE_WASABI_SECRET=$$secret__app_storage_wasabi_secret","_APP_STORAGE_WASABI_REGION=$$config__app_storage_wasabi_region","_APP_STORAGE_WASABI_BUCKET=$$config__app_storage_wasabi_bucket","DOCKERHUB_PULL_USERNAME=$$config_dockerhub_pull_username","DOCKERHUB_PULL_PASSWORD=$$secret_dockerhub_pull_password","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":["$$id-functions:/storage/functions","$$id-builds:/storage/builds","/var/run/docker.sock:/var/run/docker.sock"],"entrypoint":"executor"},"$$id-influxdb":{"image":"appwrite/influxdb:1.5.0","environment":[],"volumes":["$$id-influxdb:/var/lib/influxdb"]},"$$id-maintenance":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_DOMAIN=$$config__app_domain","_APP_DOMAIN_TARGET=$$config__app_domain_target","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_MAINTENANCE_INTERVAL=$$config__app_maintenance_interval","_APP_MAINTENANCE_RETENTION_EXECUTION=$$config__app_maintenance_retention_execution","_APP_MAINTENANCE_RETENTION_CACHE=$$config__app_maintenance_retention_cache","_APP_MAINTENANCE_RETENTION_ABUSE=$$config__app_maintenance_retention_abuse","_APP_MAINTENANCE_RETENTION_AUDIT=$$config__app_maintenance_retention_audit","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"maintenance"},"$$id-mariadb":{"image":"mariadb:10.7","command":"--innodb-flush-method fsync","environment":["MARIADB_ROOT_PASSWORD=$$secret__app_db_root_pass","MARIADB_DATABASE=$$config__app_db_schema","MARIADB_USER=$$config__app_db_user","MARIADB_PASSWORD=$$secret__app_db_pass","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":["$$id-mariadb:/var/lib/mysql"]},"$$id-realtime":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_WORKER_PER_CORE=$$config__app_worker_per_core","_APP_OPTIONS_ABUSE=$$config__app_options_abuse","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_USAGE_STATS=$$config__app_usage_stats","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"realtime","proxy":[{"port":"80","pathPrefix":"/v1/realtime"}]},"$$id-redis":{"image":"redis:7.0.4-alpine","command":"--maxmemory 512mb --maxmemory-policy allkeys-lru --maxmemory-samples 5","environment":[],"volumes":["$$id-redis:/data"]},"$$id-schedule":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"schedule"},"$$id-telegraf":{"image":"appwrite/telegraf:1.4.0","environment":["_APP_INFLUXDB_HOST=$$config__app_influxdb_host","_APP_INFLUXDB_PORT=$$config__app_influxdb_port","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":["$$id-influxdb:/var/lib/influxdb"]},"$$id-usage-database":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_INFLUXDB_HOST=$$config__app_influxdb_host","_APP_INFLUXDB_PORT=$$config__app_influxdb_port","_APP_USAGE_TIMESERIES_INTERVAL=$$config__app_usage_timeseries_interval","_APP_USAGE_DATABASE_INTERVAL=$$config__app_usage_database_interval","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"usage --type database"},"$$id-usage":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_INFLUXDB_HOST=$$config__app_influxdb_host","_APP_INFLUXDB_PORT=$$config__app_influxdb_port","_APP_USAGE_TIMESERIES_INTERVAL=$$config__app_usage_timeseries_interval","_APP_USAGE_DATABASE_INTERVAL=$$config__app_usage_database_interval","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"usage --type timeseries"},"$$id-worker-audits":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"worker-audits"},"$$id-worker-builds":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_EXECUTOR_SECRET=$$secret__app_executor_secret","_APP_EXECUTOR_HOST=$$config__app_executor_host","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"worker-builds"},"$$id-worker-certificates":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_DOMAIN=$$config__app_domain","_APP_DOMAIN_TARGET=$$config__app_domain_target","_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=$$config__app_system_security_email_address","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":["$$id-config:/storage/config","$$id-certificates:/storage/certificates"],"entrypoint":"worker-certificates"},"$$id-worker-databases":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"worker-databases"},"$$id-worker-deletes":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_STORAGE_DEVICE=$$config__app_storage_device","_APP_STORAGE_S3_ACCESS_KEY=$$secret__app_storage_s3_access_key","_APP_STORAGE_S3_SECRET=$$secret__app_storage_s3_secret","_APP_STORAGE_S3_REGION=$$config__app_storage_s3_region","_APP_STORAGE_S3_BUCKET=$$config__app_storage_s3_bucket","_APP_STORAGE_DO_SPACES_ACCESS_KEY=$$secret__app_storage_do_spaces_access_key","_APP_STORAGE_DO_SPACES_SECRET=$$secret__app_storage_do_spaces_secret","_APP_STORAGE_DO_SPACES_REGION=$$config__app_storage_do_spaces_region","_APP_STORAGE_DO_SPACES_BUCKET=$$config__app_storage_do_spaces_bucket","_APP_STORAGE_BACKBLAZE_ACCESS_KEY=$$secret__app_storage_backblaze_access_key","_APP_STORAGE_BACKBLAZE_SECRET=$$secret__app_storage_backblaze_secret","_APP_STORAGE_BACKBLAZE_REGION=$$config__app_storage_backblaze_region","_APP_STORAGE_BACKBLAZE_BUCKET=$$config__app_storage_backblaze_bucket","_APP_STORAGE_LINODE_ACCESS_KEY=$$secret__app_storage_linode_access_key","_APP_STORAGE_LINODE_SECRET=$$secret__app_storage_linode_secret","_APP_STORAGE_LINODE_REGION=$$config__app_storage_linode_region","_APP_STORAGE_LINODE_BUCKET=$$config__app_storage_linode_bucket","_APP_STORAGE_WASABI_ACCESS_KEY=$$secret__app_storage_wasabi_access_key","_APP_STORAGE_WASABI_SECRET=$$secret__app_storage_wasabi_secret","_APP_STORAGE_WASABI_REGION=$$config__app_storage_wasabi_region","_APP_STORAGE_WASABI_BUCKET=$$config__app_storage_wasabi_bucket","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","_APP_EXECUTOR_SECRET=$$secret__app_executor_secret","_APP_EXECUTOR_HOST=$$config__app_executor_host","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":["$$id-uploads:/storage/uploads","$$id-cache:/storage/cache","$$id-functions:/storage/functions","$$id-builds:/storage/builds","$$id-certificates:/storage/certificates"],"entrypoint":"worker-deletes"},"$$id-worker-functions":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_FUNCTIONS_TIMEOUT=$$config__app_functions_timeout","_APP_EXECUTOR_SECRET=$$secret__app_executor_secret","_APP_EXECUTOR_HOST=$$config__app_executor_host","_APP_USAGE_STATS=$$config__app_usage_stats","DOCKERHUB_PULL_USERNAME=$$config_dockerhub_pull_username","DOCKERHUB_PULL_PASSWORD=$$secret_dockerhub_pull_password","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"worker-functions"},"$$id-worker-mails":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_SYSTEM_EMAIL_NAME=$$config__app_system_email_name","_APP_SYSTEM_EMAIL_ADDRESS=$$config__app_system_email_address","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_SMTP_HOST=$$config__app_smtp_host","_APP_SMTP_PORT=$$config__app_smtp_port","_APP_SMTP_SECURE=$$config__app_smtp_secure","_APP_SMTP_USERNAME=$$config__app_smtp_username","_APP_SMTP_PASSWORD=$$secret__app_smtp_password","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"worker-mails"},"$$id-worker-messaging":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_SMS_PROVIDER=$$config__app_sms_provider","_APP_SMS_FROM=$$config__app_sms_from","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"worker-messaging"},"$$id-worker-webhooks":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=$$config__app_system_security_email_address","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"worker-webhooks"}},"variables":[{"id":"$$config__app_influxdb_host","name":"_APP_INFLUXDB_HOST","label":"InfluxDB | _APP_INFLUXDB_HOST","defaultValue":"$$id-influxdb","description":""},{"id":"$$config__app_influxdb_port","name":"_APP_INFLUXDB_PORT","label":"InfluxDB | _APP_INFLUXDB_PORT","defaultValue":"8086","description":"InfluxDB server TCP port."},{"id":"$$config__app_env","name":"_APP_ENV","label":"General | _APP_ENV","defaultValue":"production","description":"Set your server running environment."},{"id":"$$config__app_worker_per_core","name":"_APP_WORKER_PER_CORE","label":"General | _APP_WORKER_PER_CORE","defaultValue":"6","description":"Internal Worker per core for the API, Realtime and Executor containers. Can be configured to optimize performance."},{"id":"$$config__app_locale","name":"_APP_LOCALE","label":"General | _APP_LOCALE","defaultValue":"en","description":"Set your Appwrite's locale. By default, the locale is set to 'en'."},{"id":"$$config__app_console_whitelist_root","name":"_APP_CONSOLE_WHITELIST_ROOT","label":"General | _APP_CONSOLE_WHITELIST_ROOT","defaultValue":"enabled","description":"This option allows you to disable the creation of new users on the Appwrite console. When enabled only 1 user will be able to use the registration form. New users can be added by inviting them to your project. By default this option is enabled."},{"id":"$$config__app_console_whitelist_emails","name":"_APP_CONSOLE_WHITELIST_EMAILS","label":"General | _APP_CONSOLE_WHITELIST_EMAILS","defaultValue":"","description":"This option allows you to limit creation of new users on the Appwrite console. This option is very useful for small teams or sole developers. To enable it, pass a list of allowed email addresses separated by a comma."},{"id":"$$config__app_console_whitelist_ips","name":"_APP_CONSOLE_WHITELIST_IPS","label":"General | _APP_CONSOLE_WHITELIST_IPS","defaultValue":"","description":"This last option allows you to limit creation of users in Appwrite console for users sharing the same set of IP addresses. This option is very useful for team working with a VPN service or a company IP.\\n\\nTo enable/activate this option, pass a list of allowed IP addresses separated by a comma."},{"id":"$$config__app_system_email_name","name":"_APP_SYSTEM_EMAIL_NAME","label":"General | _APP_SYSTEM_EMAIL_NAME","defaultValue":"Appwrite","description":"This is the sender name value that will appear on email messages sent to developers from the Appwrite console. You can use url encoded strings for spaces and special chars."},{"id":"$$config__app_system_email_address","name":"_APP_SYSTEM_EMAIL_ADDRESS","label":"General | _APP_SYSTEM_EMAIL_ADDRESS","defaultValue":"team@appwrite.io","description":"This is the sender email address that will appear on email messages sent to developers from the Appwrite console. You should choose an email address that is allowed to be used from your SMTP server to avoid the server email ending in the users' SPAM folders."},{"id":"$$config__app_system_security_email_address","name":"_APP_SYSTEM_SECURITY_EMAIL_ADDRESS","label":"General | _APP_SYSTEM_SECURITY_EMAIL_ADDRESS","defaultValue":"certs@appwrite.io","description":"This is the email address used to issue SSL certificates for custom domains or the user agent in your webhooks payload."},{"id":"$$config__app_system_response_format","name":"_APP_SYSTEM_RESPONSE_FORMAT","label":"General | _APP_SYSTEM_RESPONSE_FORMAT","defaultValue":"","description":"Use this environment variable to set the default Appwrite HTTP response format to support an older version of Appwrite. This option is useful to overcome breaking changes between versions. You can also use the X-Appwrite-Response-Format HTTP request header to overwrite the response for a specific request. This variable accepts any valid Appwrite version. To use the current version format, leave the value of the variable empty."},{"id":"$$config__app_options_abuse","name":"_APP_OPTIONS_ABUSE","label":"General | _APP_OPTIONS_ABUSE","defaultValue":"enabled","description":"Allows you to disable abuse checks and API rate limiting. By default, set to 'enabled'. To cancel the abuse checking, set to 'disabled'. It is not recommended to disable this check-in a production environment."},{"id":"$$config__app_options_force_https","name":"_APP_OPTIONS_FORCE_HTTPS","label":"General | _APP_OPTIONS_FORCE_HTTPS","defaultValue":"disabled","description":"Allows you to force HTTPS connection to your API. This feature redirects any HTTP call to HTTPS and adds the 'Strict-Transport-Security' header to all HTTP responses."},{"id":"$$secret__app_openssl_key_v1","name":"_APP_OPENSSL_KEY_V1","label":"General | _APP_OPENSSL_KEY_V1","defaultValue":"$$generate_hex(256)","description":"This is your server private secret key that is used to encrypt all sensitive data on your server. Appwrite server encrypts all secret data on your server like webhooks, HTTP passwords, user sessions, and storage files. Keep it a secret and have a backup for it."},{"id":"$$config__app_domain","name":"_APP_DOMAIN","label":"General | _APP_DOMAIN","defaultValue":"$$generate_domain","description":"Your Appwrite domain address. When setting a public suffix domain, Appwrite will attempt to issue a valid SSL certificate automatically. When used with a dev domain, Appwrite will assign a self-signed SSL certificate. The default value is 'localhost'."},{"id":"$$config__app_domain_target","name":"_APP_DOMAIN_TARGET","label":"General | _APP_DOMAIN_TARGET","defaultValue":"$$generate_fqdn","description":"A DNS A record hostname to serve as a CNAME target for your Appwrite custom domains. You can use the same value as used for the Appwrite '_APP_DOMAIN' variable. The default value is 'localhost'."},{"id":"$$config__app_redis_host","name":"_APP_REDIS_HOST","label":"Redis | _APP_REDIS_HOST","defaultValue":"$$id-redis","description":""},{"id":"$$config__app_redis_port","name":"_APP_REDIS_PORT","label":"Redis | _APP_REDIS_PORT","defaultValue":"6379","description":"Redis server TCP port."},{"id":"$$config__app_redis_user","name":"_APP_REDIS_USER","label":"Redis | _APP_REDIS_USER","defaultValue":"","description":"Redis server user. This is an optional variable. Default value is an empty string."},{"id":"$$secret__app_redis_pass","name":"_APP_REDIS_PASS","label":"Redis | _APP_REDIS_PASS","defaultValue":"","description":"Redis server password. This is an optional variable. Default value is an empty string."},{"id":"$$config__app_db_host","name":"_APP_DB_HOST","label":"MariaDB | _APP_DB_HOST","defaultValue":"$$id-mariadb","description":""},{"id":"$$config__app_db_port","name":"_APP_DB_PORT","label":"MariaDB | _APP_DB_PORT","defaultValue":"3306","description":"MariaDB server TCP port."},{"id":"$$config__app_db_schema","name":"_APP_DB_SCHEMA","label":"MariaDB | _APP_DB_SCHEMA","defaultValue":"appwrite","description":"MariaDB server database schema."},{"id":"$$config__app_db_user","name":"_APP_DB_USER","label":"MariaDB | _APP_DB_USER","defaultValue":"user","description":"MariaDB server user name."},{"id":"$$secret__app_db_root_pass","name":"MARIADB_ROOT_PASSWORD","label":"MariaDB | MARIADB_ROOT_PASSWORD","defaultValue":"$$generate_hex(16)","description":"MariaDB server root user password."},{"id":"$$secret__app_db_pass","name":"_APP_DB_PASS","label":"MariaDB | _APP_DB_PASS","defaultValue":"$$generate_hex(16)","description":"MariaDB server user password."},{"id":"$$config__app_smtp_host","name":"_APP_SMTP_HOST","label":"SMTP | _APP_SMTP_HOST","defaultValue":"","description":"SMTP server host name address. Use an empty string to disable all mail sending from the server. The default value for this variable is an empty string."},{"id":"$$config__app_smtp_port","name":"_APP_SMTP_PORT","label":"SMTP | _APP_SMTP_PORT","defaultValue":"","description":"SMTP server TCP port. Empty by default."},{"id":"$$config__app_smtp_secure","name":"_APP_SMTP_SECURE","label":"SMTP | _APP_SMTP_SECURE","defaultValue":"","description":"SMTP secure connection protocol. Empty by default, change to 'tls' if running on a secure connection."},{"id":"$$config__app_smtp_username","name":"_APP_SMTP_USERNAME","label":"SMTP | _APP_SMTP_USERNAME","defaultValue":"","description":"SMTP server user name. Empty by default."},{"id":"$$secret__app_smtp_password","name":"_APP_SMTP_PASSWORD","label":"SMTP | _APP_SMTP_PASSWORD","defaultValue":"","description":"SMTP server user password. Empty by default."},{"id":"$$config__app_usage_stats","name":"_APP_USAGE_STATS","label":"General | _APP_USAGE_STATS","defaultValue":"enabled","description":"This variable allows you to disable the collection and displaying of usage stats. This value is set to 'enabled' by default, to disable the usage stats set the value to 'disabled'. When disabled, it's recommended to turn off the Worker Usage, Influxdb and Telegraf containers for better resource usage."},{"id":"$$config__app_storage_limit","name":"_APP_STORAGE_LIMIT","label":"Storage | _APP_STORAGE_LIMIT","defaultValue":"30000000","description":"Maximum file size allowed for file upload. The default value is 30MB. You should pass your size limit value in bytes."},{"id":"$$config__app_storage_preview_limit","name":"_APP_STORAGE_PREVIEW_LIMIT","label":"Storage | _APP_STORAGE_PREVIEW_LIMIT","defaultValue":"20000000","description":"Maximum file size allowed for file image preview. The default value is 20MB. You should pass your size limit value in bytes."},{"id":"$$config__app_storage_antivirus_enabled","name":"_APP_STORAGE_ANTIVIRUS","label":"Storage | _APP_STORAGE_ANTIVIRUS","defaultValue":"disabled","description":"This variable allows you to disable the internal anti-virus scans. This value is set to 'disabled' by default, to enable the scans set the value to 'enabled'. Before enabling, you must add the ClamAV service and depend on it on main Appwrite service."},{"id":"$$config__app_storage_antivirus_host","name":"_APP_STORAGE_ANTIVIRUS_HOST","label":"Storage | _APP_STORAGE_ANTIVIRUS_HOST","defaultValue":"clamav","description":"ClamAV server host name address."},{"id":"$$config__app_storage_antivirus_port","name":"_APP_STORAGE_ANTIVIRUS_PORT","label":"Storage | _APP_STORAGE_ANTIVIRUS_PORT","defaultValue":"3310","description":"ClamAV server TCP port."},{"id":"$$config__app_storage_device","name":"_APP_STORAGE_DEVICE","label":"Storage | _APP_STORAGE_DEVICE","defaultValue":"Local","description":"Select default storage device. The default value is 'Local'. List of supported adapters are 'Local', 'S3', 'DOSpaces', 'Backblaze', 'Linode' and 'Wasabi'."},{"id":"$$secret__app_storage_s3_access_key","name":"_APP_STORAGE_S3_ACCESS_KEY","label":"Storage | _APP_STORAGE_S3_ACCESS_KEY","defaultValue":"","description":"AWS S3 storage access key. Required when the storage adapter is set to S3. You can get your access key from your AWS console."},{"id":"$$secret__app_storage_s3_secret","name":"_APP_STORAGE_S3_SECRET","label":"Storage | _APP_STORAGE_S3_SECRET","defaultValue":"","description":"AWS S3 storage secret key. Required when the storage adapter is set to S3. You can get your secret key from your AWS console."},{"id":"$$config__app_storage_s3_region","name":"_APP_STORAGE_S3_REGION","label":"Storage | _APP_STORAGE_S3_REGION","defaultValue":"us-east-1","description":"AWS S3 storage region. Required when storage adapter is set to S3. You can find your region info for your bucket from AWS console."},{"id":"$$config__app_storage_s3_bucket","name":"_APP_STORAGE_S3_BUCKET","label":"Storage | _APP_STORAGE_S3_BUCKET","defaultValue":"","description":"AWS S3 storage bucket. Required when storage adapter is set to S3. You can create buckets in your AWS console."},{"id":"$$secret__app_storage_do_spaces_access_key","name":"_APP_STORAGE_DO_SPACES_ACCESS_KEY","label":"Storage | _APP_STORAGE_DO_SPACES_ACCESS_KEY","defaultValue":"","description":"DigitalOcean spaces access key. Required when the storage adapter is set to DOSpaces. You can get your access key from your DigitalOcean console."},{"id":"$$secret__app_storage_do_spaces_secret","name":"_APP_STORAGE_DO_SPACES_SECRET","label":"Storage | _APP_STORAGE_DO_SPACES_SECRET","defaultValue":"","description":"DigitalOcean spaces secret key. Required when the storage adapter is set to DOSpaces. You can get your secret key from your DigitalOcean console."},{"id":"$$config__app_storage_do_spaces_region","name":"_APP_STORAGE_DO_SPACES_REGION","label":"Storage | _APP_STORAGE_DO_SPACES_REGION","defaultValue":"us-east-1","description":"DigitalOcean spaces region. Required when storage adapter is set to DOSpaces. You can find your region info for your space from DigitalOcean console."},{"id":"$$config__app_storage_do_spaces_bucket","name":"_APP_STORAGE_DO_SPACES_BUCKET","label":"Storage | _APP_STORAGE_DO_SPACES_BUCKET","defaultValue":"","description":"DigitalOcean spaces bucket. Required when storage adapter is set to DOSpaces. You can create spaces in your DigitalOcean console."},{"id":"$$secret__app_storage_backblaze_access_key","name":"_APP_STORAGE_BACKBLAZE_ACCESS_KEY","label":"Storage | _APP_STORAGE_BACKBLAZE_ACCESS_KEY","defaultValue":"","description":"Backblaze access key. Required when the storage adapter is set to Backblaze. Your Backblaze keyID will be your access key. You can get your keyID from your Backblaze console."},{"id":"$$secret__app_storage_backblaze_secret","name":"_APP_STORAGE_BACKBLAZE_SECRET","label":"Storage | _APP_STORAGE_BACKBLAZE_SECRET","defaultValue":"","description":"Backblaze secret key. Required when the storage adapter is set to Backblaze. Your Backblaze applicationKey will be your secret key. You can get your applicationKey from your Backblaze console."},{"id":"$$config__app_storage_backblaze_region","name":"_APP_STORAGE_BACKBLAZE_REGION","label":"Storage | _APP_STORAGE_BACKBLAZE_REGION","defaultValue":"us-west-004","description":"Backblaze region. Required when storage adapter is set to Backblaze. You can find your region info from your Backblaze console."},{"id":"$$config__app_storage_backblaze_bucket","name":"_APP_STORAGE_BACKBLAZE_BUCKET","label":"Storage | _APP_STORAGE_BACKBLAZE_BUCKET","defaultValue":"","description":"Backblaze bucket. Required when storage adapter is set to Backblaze. You can create your bucket from your Backblaze console."},{"id":"$$secret__app_storage_linode_access_key","name":"_APP_STORAGE_LINODE_ACCESS_KEY","label":"Storage | _APP_STORAGE_LINODE_ACCESS_KEY","defaultValue":"","description":"Linode object storage access key. Required when the storage adapter is set to Linode. You can get your access key from your Linode console."},{"id":"$$secret__app_storage_linode_secret","name":"_APP_STORAGE_LINODE_SECRET","label":"Storage | _APP_STORAGE_LINODE_SECRET","defaultValue":"","description":"Linode object storage secret key. Required when the storage adapter is set to Linode. You can get your secret key from your Linode console."},{"id":"$$config__app_storage_linode_region","name":"_APP_STORAGE_LINODE_REGION","label":"Storage | _APP_STORAGE_LINODE_REGION","defaultValue":"eu-central-1","description":"Linode object storage region. Required when storage adapter is set to Linode. You can find your region info from your Linode console."},{"id":"$$config__app_storage_linode_bucket","name":"_APP_STORAGE_LINODE_BUCKET","label":"Storage | _APP_STORAGE_LINODE_BUCKET","defaultValue":"","description":"Linode object storage bucket. Required when storage adapter is set to Linode. You can create buckets in your Linode console."},{"id":"$$secret__app_storage_wasabi_access_key","name":"_APP_STORAGE_WASABI_ACCESS_KEY","label":"Storage | _APP_STORAGE_WASABI_ACCESS_KEY","defaultValue":"","description":"Wasabi access key. Required when the storage adapter is set to Wasabi. You can get your access key from your Wasabi console."},{"id":"$$secret__app_storage_wasabi_secret","name":"_APP_STORAGE_WASABI_SECRET","label":"Storage | _APP_STORAGE_WASABI_SECRET","defaultValue":"","description":"Wasabi secret key. Required when the storage adapter is set to Wasabi. You can get your secret key from your Wasabi console."},{"id":"$$config__app_storage_wasabi_region","name":"_APP_STORAGE_WASABI_REGION","label":"Storage | _APP_STORAGE_WASABI_REGION","defaultValue":"eu-central-1","description":"Wasabi region. Required when storage adapter is set to Wasabi. You can find your region info from your Wasabi console."},{"id":"$$config__app_storage_wasabi_bucket","name":"_APP_STORAGE_WASABI_BUCKET","label":"Storage | _APP_STORAGE_WASABI_BUCKET","defaultValue":"","description":"Wasabi bucket. Required when storage adapter is set to Wasabi. You can create buckets in your Wasabi console."},{"id":"$$config__app_functions_size_limit","name":"_APP_FUNCTIONS_SIZE_LIMIT","label":"Functions | _APP_FUNCTIONS_SIZE_LIMIT","defaultValue":"30000000","description":"The maximum size deployment in bytes. The default value is 30MB."},{"id":"$$config__app_functions_timeout","name":"_APP_FUNCTIONS_TIMEOUT","label":"Functions | _APP_FUNCTIONS_TIMEOUT","defaultValue":"900","description":"The maximum number of seconds allowed as a timeout value when creating a new function. The default value is 900 seconds."},{"id":"$$config__app_functions_build_timeout","name":"_APP_FUNCTIONS_BUILD_TIMEOUT","label":"Functions | _APP_FUNCTIONS_BUILD_TIMEOUT","defaultValue":"900","description":"The maximum number of seconds allowed as a timeout value when building a new function. The default value is 900 seconds."},{"id":"$$config__app_functions_containers","name":"_APP_FUNCTIONS_CONTAINERS","label":"Functions | _APP_FUNCTIONS_CONTAINERS","defaultValue":"10","description":"The maximum number of containers Appwrite is allowed to keep alive in the background for function environments. Running containers allow faster execution time as there is no need to recreate each container every time a function gets executed. The default value is 10."},{"id":"$$config__app_functions_cpus","name":"_APP_FUNCTIONS_CPUS","label":"Functions | _APP_FUNCTIONS_CPUS","defaultValue":"","description":"The maximum number of CPU core a single cloud function is allowed to use. Please note that setting a value higher than available cores will result in a function error, which might result in an error. The default value is empty. When it's empty, CPU limit will be disabled."},{"id":"$$config__app_functions_memory_allocated","name":"_APP_FUNCTIONS_MEMORY","label":"Functions | _APP_FUNCTIONS_MEMORY","defaultValue":"","description":"The maximum amount of memory a single cloud function is allowed to use in megabytes. The default value is empty. When it's empty, memory limit will be disabled."},{"id":"$$config__app_functions_memory_swap","name":"_APP_FUNCTIONS_MEMORY_SWAP","label":"Functions | _APP_FUNCTIONS_MEMORY_SWAP","defaultValue":"","description":"The maximum amount of swap memory a single cloud function is allowed to use in megabytes. The default value is empty. When it's empty, swap memory limit will be disabled."},{"id":"$$config__app_functions_runtimes","name":"_APP_FUNCTIONS_RUNTIMES","label":"Functions | _APP_FUNCTIONS_RUNTIMES","defaultValue":"node-18.0","description":"This option allows you to limit the available environments for cloud functions. This option is very useful for low-cost servers to safe disk space.\nTo enable/activate this option, pass a list of allowed environments separated by a comma.\nCurrently, supported environments are: node-14.5, node-16.0, node-18.0, php-8.0, php-8.1, ruby-3.0, ruby-3.1, python-3.8, python-3.9, python-3.10, deno-1.21, deno-1.24, dart-2.15, dart-2.16, dart-2.17, dotnet-3.1, dotnet-6.0, java-8.0, java-11.0, java-17.0, java-18.0, swift-5.5, kotlin-1.6, cpp-17.0"},{"id":"$$secret__app_executor_secret","name":"_APP_EXECUTOR_SECRET","label":"Functions | _APP_EXECUTOR_SECRET","defaultValue":"$$generate_hex(16)","description":"The secret key used by Appwrite to communicate with the function executor."},{"id":"$$config__app_executor_host","name":"_APP_EXECUTOR_HOST","label":"","defaultValue":"http://$$id-executor/v1","description":""},{"id":"$$config__app_logging_provider","name":"_APP_LOGGING_PROVIDER","label":"General | _APP_LOGGING_PROVIDER","defaultValue":"","description":"This variable allows you to enable logging errors to 3rd party providers. This value is empty by default, to enable the logger set the value to one of 'sentry', 'raygun', 'appsignal', 'logowl'"},{"id":"$$config__app_logging_config","name":"_APP_LOGGING_CONFIG","label":"General | _APP_LOGGING_CONFIG","defaultValue":"","description":"This variable configures authentication to 3rd party error logging providers. If using Sentry, this should be 'SENTRY_API_KEY;SENTRY_APP_ID'. If using Raygun, this should be Raygun API key. If using AppSignal, this should be AppSignal API key. If using LogOwl, this should be LogOwl Service Ticket."},{"id":"$$config__app_statsd_host","name":"_APP_STATSD_HOST","label":"","defaultValue":"$$id-telegraf","description":""},{"id":"$$config__app_statsd_port","name":"_APP_STATSD_PORT","label":"StatsD | _APP_STATSD_PORT","defaultValue":"8125","description":"StatsD server TCP port."},{"id":"$$config__app_maintenance_interval","name":"_APP_MAINTENANCE_INTERVAL","label":"Functions | _APP_MAINTENANCE_INTERVAL","defaultValue":"86400","description":"Interval value containing the number of seconds that the Appwrite maintenance process should wait before executing system cleanups and optimizations. The default value is 86400 seconds (1 day)."},{"id":"$$config__app_maintenance_retention_execution","name":"_APP_MAINTENANCE_RETENTION_EXECUTION","label":"Functions | _APP_MAINTENANCE_RETENTION_EXECUTION","defaultValue":"1209600","description":"The maximum duration (in seconds) upto which to retain execution logs. The default value is 1209600 seconds (14 days)."},{"id":"$$config__app_maintenance_retention_cache","name":"_APP_MAINTENANCE_RETENTION_CACHE","label":"Functions | _APP_MAINTENANCE_RETENTION_CACHE","defaultValue":"2592000","description":"The maximum duration (in seconds) upto which to retain cached files. The default value is 2592000 seconds (30 days)."},{"id":"$$config__app_maintenance_retention_abuse","name":"_APP_MAINTENANCE_RETENTION_ABUSE","label":"Functions | _APP_MAINTENANCE_RETENTION_ABUSE","defaultValue":"86400","description":"The maximum duration (in seconds) upto which to retain abuse logs. The default value is 86400 seconds (1 day)."},{"id":"$$config__app_maintenance_retention_audit","name":"_APP_MAINTENANCE_RETENTION_AUDIT","label":"Functions | _APP_MAINTENANCE_RETENTION_AUDIT","defaultValue":"1209600","description":"The maximum duration (in seconds) upto which to retain audit logs. The default value is 1209600 seconds (14 days)."},{"id":"$$config__app_sms_provider","name":"_APP_SMS_PROVIDER","label":"Phone | _APP_SMS_PROVIDER","defaultValue":"","description":"Provider used for delivering SMS for Phone authentication. Use the following format: 'sms://[USER]:[SECRET]@[PROVIDER]'. Available providers are twilio, text-magic, telesign, msg91, and vonage."},{"id":"$$config__app_sms_from","name":"_APP_SMS_FROM","label":"Phone | _APP_SMS_FROM","defaultValue":"","description":"Phone number used for sending out messages. Must start with a leading '+' and maximum of 15 digits without spaces (+123456789)."},{"id":"$$config__app_functions_inactive_threshold","name":"_APP_FUNCTIONS_INACTIVE_THRESHOLD","label":"Functions | _APP_FUNCTIONS_INACTIVE_THRESHOLD","defaultValue":"60","description":"The minimum time a function can be inactive before it's container is shutdown and put to sleep. The default value is 60 seconds"},{"id":"$$config_open_runtimes_network","name":"OPEN_RUNTIMES_NETWORK","label":"","defaultValue":"$$generate_network","description":""},{"id":"$$config_dockerhub_pull_username","name":"DOCKERHUB_PULL_USERNAME","label":"Functions | DOCKERHUB_PULL_USERNAME","defaultValue":"","description":"The username for hub.docker.com. This variable is used to pull images from hub.docker.com."},{"id":"$$secret_dockerhub_pull_password","name":"DOCKERHUB_PULL_PASSWORD","label":"Functions | DOCKERHUB_PULL_PASSWORD","defaultValue":"","description":"The password for hub.docker.com. This variable is used to pull images from hub.docker.com."},{"id":"$$config__app_usage_timeseries_interval","name":"_APP_USAGE_TIMESERIES_INTERVAL","label":"General | _APP_USAGE_TIMESERIES_INTERVAL","defaultValue":"30","description":"Interval value containing the number of seconds that the Appwrite usage process should wait before aggregating stats and syncing it to mariadb from InfluxDB. The default value is 30 seconds."},{"id":"$$config__app_usage_database_interval","name":"_APP_USAGE_DATABASE_INTERVAL","label":"General | _APP_USAGE_DATABASE_INTERVAL","defaultValue":"900","description":"Interval value containing the number of seconds that the Appwrite usage process should wait before aggregating stats from data in Appwrite Database. The default value is 15 minutes."}]},{"templateVersion":"1.0.0","defaultVersion":"latest","documentation":"https://docs.weblate.org/en/latest/admin/install/docker.html","description":"A copylefted libre software web-based continuous localization system.","type":"weblate","name":"Weblate","labels":["translate","localization"],"services":{"$$id":{"name":"Weblate","depends_on":["$$id-postgresql","$$id-redis"],"image":"weblate/weblate:$$core_version","volumes":["$$id-data:/app/data"],"environment":["WEBLATE_SITE_DOMAIN=$$config_weblate_site_domain","WEBLATE_ADMIN_PASSWORD=$$secret_weblate_admin_password","POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_USER=$$config_postgres_user","POSTGRES_DATABASE=$$config_postgres_db","POSTGRES_HOST=$$id-postgresql","POSTGRES_PORT=5432","REDIS_HOST=$$id-redis"],"ports":["8080"]},"$$id-postgresql":{"name":"PostgreSQL","depends_on":[],"image":"postgres:14-alpine","volumes":["$$id-postgresql-data:/var/lib/postgresql/data"],"environment":["POSTGRES_USER=$$config_postgres_user","POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_DB=$$config_postgres_db"],"ports":[]},"$$id-redis":{"name":"Redis","depends_on":[],"image":"redis:7-alpine","volumes":["$$id-redis-data:/data"],"environment":[],"ports":[]}},"variables":[{"id":"$$config_weblate_site_domain","name":"WEBLATE_SITE_DOMAIN","label":"Weblate Domain","defaultValue":"$$generate_domain","description":""},{"id":"$$secret_weblate_admin_password","name":"WEBLATE_ADMIN_PASSWORD","label":"Weblate Admin Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_postgres_user","main":"$$id-postgresql","name":"POSTGRES_USER","label":"PostgreSQL User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_postgres_password","main":"$$id-postgresql","name":"POSTGRES_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_postgres_db","main":"$$id-postgresql","name":"POSTGRES_DB","label":"PostgreSQL Database","defaultValue":"weblate","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"2022.10.14-1a5b0965","documentation":"https://docs.searxng.org/","type":"searxng","name":"SearXNG","description":"Free internet metasearch engine which aggregates results from more than 70 search services.","services":{"$$id":{"name":"SearXNG","depends_on":["$$id-redis"],"image":"searxng/searxng:$$core_version","volumes":["$$id-searxng:/etc/searxng"],"environment":["SEARXNG_BASE_URL=$$config_searxng_base_url"],"ports":["8080"],"cap_drop":["ALL"],"cap_add":["CHOWN","SETGID","SETUID","DAC_OVERRIDE"],"files":[{"location":"/etc/searxng/settings.yml","content":"\n # see https://docs.searxng.org/admin/engines/settings.html#use-default-settings\n use_default_settings: true\n server:\n secret_key: $$secret_secret_key\n limiter: true\n image_proxy: true\n ui:\n static_use_hash: true\n redis:\n url: redis://:$$secret_redis_password@$$id-redis:6379/0"}]},"$$id-redis":{"name":"Redis","command":"redis-server --requirepass $$secret_redis_password --save \"\" --appendonly \"no\"","depends_on":[],"image":"redis:7-alpine","volumes":["$$id-redis-data:/data"],"environment":["REDIS_PASSWORD=$$secret_redis_password"],"ports":[],"cap_drop":["ALL"],"cap_add":["SETGID","SETUID","DAC_OVERRIDE"]}},"variables":[{"id":"$$config_searxng_base_url","name":"SEARXNG_BASE_URL","label":"SearXNG Base URL","defaultValue":"$$generate_fqdn","description":""},{"id":"$$secret_secret_key","name":"SECRET_KEY","label":"Secret Key","defaultValue":"$$generate_hex(64)","description":""},{"id":"$$secret_redis_password","name":"REDIS_PASSWORD","label":"Redis Password","defaultValue":"$$generate_password","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"v2.0.6","documentation":"https://glitchtip.com/documentation","type":"glitchtip","name":"GlitchTip","description":"Simple, open source error tracking.","labels":["sentry","bugsnag"],"services":{"$$id":{"name":"GlitchTip","depends_on":["$$id-postgresql","$$id-redis"],"image":"glitchtip/glitchtip:$$core_version","volumes":[],"environment":["PORT=$$config_port","GLITCHTIP_DOMAIN=$$config_glitchtip_domain","SECRET_KEY=$$secret_secret_key","DATABASE_URL=$$secret_database_url","REDIS_URL=$$secret_redis_url","DEFAULT_FROM_EMAIL=$$config_default_from_email","EMAIL_URL=$$secret_email_url","EMAIL_HOST=$$config_email_host","EMAIL_PORT=$$config_email_port","EMAIL_HOST_USER=$$config_email_host_user","EMAIL_HOST_PASSWORD=$$secret_email_host_password","EMAIL_USE_TLS=$$config_email_use_tls","EMAIL_USE_SSL=$$config_email_use_ssl","EMAIL_BACKEND=$$config_email_backend","MAILGUN_API_KEY=$$secret_mailgun_api_key","SENDGRID_API_KEY=$$secret_sendgrid_api_key","ENABLE_OPEN_USER_REGISTRATION=$$config_enable_open_user_registration","DJANGO_SUPERUSER_EMAIL=$$config_django_superuser_email","DJANGO_SUPERUSER_PASSWORD=$$secret_django_superuser_password","DJANGO_SUPERUSER_USERNAME=$$config_django_superuser_username","CELERY_WORKER_CONCURRENCY=$$config_celery_worker_concurrency"],"ports":["8000"]},"$$id-worker":{"name":"Celery Worker","command":"./bin/run-celery-with-beat.sh","depends_on":["$$id-postgresql","$$id-redis"],"image":"glitchtip/glitchtip:$$core_version","environment":["GLITCHTIP_DOMAIN=$$config_glitchtip_domain","SECRET_KEY=$$secret_secret_key","DATABASE_URL=$$secret_database_url","REDIS_URL=$$secret_redis_url","DEFAULT_FROM_EMAIL=$$config_default_from_email","EMAIL_URL=$$secret_email_url","CELERY_WORKER_CONCURRENCY=$$config_celery_worker_concurrency"],"ports":[]},"$$id-migrate":{"exclude":true,"name":"Migrate","command":"./manage.py migrate","depends_on":["$$id-postgresql","$$id-redis"],"image":"glitchtip/glitchtip:$$core_version","environment":["GLITCHTIP_DOMAIN=$$config_glitchtip_domain","SECRET_KEY=$$secret_secret_key","DATABASE_URL=$$secret_database_url","REDIS_URL=$$secret_redis_url","DEFAULT_FROM_EMAIL=$$config_default_from_email","EMAIL_URL=$$secret_email_url"],"ports":[]},"$$id-postgresql":{"name":"PostgreSQL","depends_on":[],"image":"postgres:14-alpine","volumes":["$$id-postgresql-data:/var/lib/postgresql/data"],"environment":["POSTGRES_USER=$$config_postgres_user","POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_DB=$$config_postgres_db"],"ports":[]},"$$id-redis":{"name":"Redis","depends_on":[],"image":"redis:7-alpine","volumes":["$$id-postgresql-redis-data:/data"],"environment":[],"ports":[]}},"variables":[{"id":"$$config_django_superuser_username","name":"DJANGO_SUPERUSER_USERNAME","label":"Django Superuser Username","defaultValue":"$$generate_username","description":""},{"id":"$$secret_django_superuser_password","name":"DJANGO_SUPERUSER_PASSWORD","label":"Django Superuser Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_port","name":"PORT","label":"GlitchTip Port","defaultValue":"8000","description":""},{"id":"$$config_celery_worker_concurrency","main":"$$id-worker","name":"CELERY_WORKER_CONCURRENCY","label":"Celery Worker Concurrency","defaultValue":"2","description":""},{"id":"$$config_glitchtip_domain","name":"GLITCHTIP_DOMAIN","label":"GlitchTip Domain","defaultValue":"$$generate_fqdn","description":""},{"id":"$$secret_email_url","name":"EMAIL_URL","label":"SMTP Email URL","defaultValue":"smtp://$$config_email_host_user:$$secret_email_host_password@$$config_email_host:$$config_email_port","description":""},{"id":"$$secret_database_url","name":"DATABASE_URL","label":"Database URL for PostgreSQL","defaultValue":"postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db","description":""},{"id":"$$secret_redis_url","name":"REDIS_URL","label":"Redis URL","defaultValue":"redis://$$id-redis:6379/0","description":""},{"id":"$$config_default_from_email","name":"DEFAULT_FROM_EMAIL","label":"Default Email Address","defaultValue":"noreply@example.com","description":""},{"id":"$$config_email_host","name":"EMAIL_HOST","label":"Email SMTP Host","defaultValue":"","description":""},{"id":"$$config_email_port","name":"EMAIL_PORT","label":"Email SMTP Port","defaultValue":"25","description":""},{"id":"$$config_email_host_user","name":"EMAIL_HOST_USER","label":"Email SMTP User","defaultValue":"","description":""},{"id":"$$secret_email_host_password","name":"EMAIL_HOST_PASSWORD","label":"Email SMTP Password","defaultValue":"","description":""},{"id":"$$config_email_use_tls","name":"EMAIL_USE_TLS","label":"Email Use TLS","defaultValue":"false","description":""},{"id":"$$config_email_use_ssl","name":"EMAIL_USE_SSL","label":"Email Use SSL","defaultValue":"false","description":""},{"id":"$$secret_email_smtp_password","name":"EMAIL_SMTP_PASSWORD","label":"SMTP Password","defaultValue":"","description":""},{"id":"$$config_email_backend","name":"EMAIL_BACKEND","label":"Email Backend","defaultValue":"","description":""},{"id":"$$secret_mailgun_api_key","name":"MAILGUN_API_KEY","label":"Mailgun API Key","defaultValue":"","description":"","showOnConfiguration":true},{"id":"$$secret_sendgrid_api_key","name":"SENDGRID_API_KEY","label":"Sendgrid API Key","defaultValue":"","description":"","showOnConfiguration":true},{"id":"$$config_enable_open_user_registration","name":"ENABLE_OPEN_USER_REGISTRATION","label":"Enable Open User Registration","defaultValue":"true","description":""},{"id":"$$config_django_superuser_email","name":"DJANGO_SUPERUSER_EMAIL","label":"Django Superuser Email","defaultValue":"noreply@example.com","description":""},{"id":"$$config_postgres_user","main":"$$id-postgresql","name":"POSTGRES_USER","label":"PostgreSQL User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_postgres_password","main":"$$id-postgresql","name":"POSTGRES_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":""},{"id":"$$config_postgres_db","main":"$$id-postgresql","name":"POSTGRES_DB","label":"PostgreSQL Database","defaultValue":"glitchtip","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"v2.13.0","documentation":"https://hasura.io/docs/latest/index/","type":"hasura","name":"Hasura","description":"Instant realtime GraphQL APIs on any Postgres application, existing or new.","labels":["graphql","database"],"services":{"$$id":{"name":"Hasura","depends_on":["$$id-postgresql"],"image":"hasura/graphql-engine:$$core_version","volumes":[],"environment":["HASURA_GRAPHQL_ENABLE_CONSOLE=$$config_hasura_graphql_enable_console","HASURA_GRAPHQL_METADATA_DATABASE_URL=$$secret_hasura_graphql_metadata_database_url","HASURA_GRAPHQL_ADMIN_SECRET=$$secret_hasura_graphql_admin_secret"],"ports":["8080"]},"$$id-postgresql":{"name":"PostgreSQL","depends_on":[],"image":"postgres:12-alpine","volumes":["$$id-postgresql-data:/var/lib/postgresql/data"],"environment":["POSTGRES_USER=$$config_postgres_user","POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_DB=$$config_postgres_db"],"ports":[]}},"variables":[{"id":"$$config_hasura_graphql_enable_console","name":"HASURA_GRAPHQL_ENABLE_CONSOLE","label":"Enable Hasura Console","defaultValue":"true","description":""},{"id":"$$secret_hasura_graphql_metadata_database_url","name":"HASURA_GRAPHQL_METADATA_DATABASE_URL","label":"Hasura Metadata Database URL","defaultValue":"postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db","description":""},{"id":"$$secret_hasura_graphql_admin_secret","name":"HASURA_GRAPHQL_ADMIN_SECRET","label":"Hasura Admin Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_postgres_user","name":"POSTGRES_USER","label":"PostgreSQL User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_postgres_password","name":"POSTGRES_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":""},{"id":"$$config_postgres_db","name":"POSTGRES_DB","label":"PostgreSQL Database","defaultValue":"hasura","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"postgresql-v1.38.0","documentation":"https://umami.is/docs/getting-started","type":"umami-postgresql","name":"Umami","subname":"(PostgreSQL)","description":"A simple, easy to use, self-hosted web analytics solution.","services":{"$$id":{"name":"Umami","depends_on":["$$id-postgresql"],"image":"ghcr.io/umami-software/umami:$$core_version","volumes":[],"environment":["ADMIN_PASSWORD=$$secret_admin_password","DATABASE_URL=$$secret_database_url","DATABASE_TYPE=$$config_database_type","HASH_SALT=$$secret_hash_salt"],"ports":["3000"]},"$$id-postgresql":{"name":"PostgreSQL","depends_on":[],"image":"postgres:12-alpine","volumes":["$$id-postgresql-data:/var/lib/postgresql/data"],"environment":["POSTGRES_USER=$$config_postgres_user","POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_DB=$$config_postgres_db"],"ports":[],"files":[{"location":"/docker-entrypoint-initdb.d/schema.postgresql.sql","content":"\n -- CreateTable\n CREATE TABLE \"account\" (\n \"user_id\" SERIAL NOT NULL,\n \"username\" VARCHAR(255) NOT NULL,\n \"password\" VARCHAR(60) NOT NULL,\n \"is_admin\" BOOLEAN NOT NULL DEFAULT false,\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \"updated_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \n PRIMARY KEY (\"user_id\")\n );\n \n -- CreateTable\n CREATE TABLE \"event\" (\n \"event_id\" SERIAL NOT NULL,\n \"website_id\" INTEGER NOT NULL,\n \"session_id\" INTEGER NOT NULL,\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \"url\" VARCHAR(500) NOT NULL,\n \"event_type\" VARCHAR(50) NOT NULL,\n \"event_value\" VARCHAR(50) NOT NULL,\n \n PRIMARY KEY (\"event_id\")\n );\n \n -- CreateTable\n CREATE TABLE \"pageview\" (\n \"view_id\" SERIAL NOT NULL,\n \"website_id\" INTEGER NOT NULL,\n \"session_id\" INTEGER NOT NULL,\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \"url\" VARCHAR(500) NOT NULL,\n \"referrer\" VARCHAR(500),\n \n PRIMARY KEY (\"view_id\")\n );\n \n -- CreateTable\n CREATE TABLE \"session\" (\n \"session_id\" SERIAL NOT NULL,\n \"session_uuid\" UUID NOT NULL,\n \"website_id\" INTEGER NOT NULL,\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \"hostname\" VARCHAR(100),\n \"browser\" VARCHAR(20),\n \"os\" VARCHAR(20),\n \"device\" VARCHAR(20),\n \"screen\" VARCHAR(11),\n \"language\" VARCHAR(35),\n \"country\" CHAR(2),\n \n PRIMARY KEY (\"session_id\")\n );\n \n -- CreateTable\n CREATE TABLE \"website\" (\n \"website_id\" SERIAL NOT NULL,\n \"website_uuid\" UUID NOT NULL,\n \"user_id\" INTEGER NOT NULL,\n \"name\" VARCHAR(100) NOT NULL,\n \"domain\" VARCHAR(500),\n \"share_id\" VARCHAR(64),\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \n PRIMARY KEY (\"website_id\")\n );\n \n -- CreateIndex\n CREATE UNIQUE INDEX \"account.username_unique\" ON \"account\"(\"username\");\n \n -- CreateIndex\n CREATE INDEX \"event_created_at_idx\" ON \"event\"(\"created_at\");\n \n -- CreateIndex\n CREATE INDEX \"event_session_id_idx\" ON \"event\"(\"session_id\");\n \n -- CreateIndex\n CREATE INDEX \"event_website_id_idx\" ON \"event\"(\"website_id\");\n \n -- CreateIndex\n CREATE INDEX \"pageview_created_at_idx\" ON \"pageview\"(\"created_at\");\n \n -- CreateIndex\n CREATE INDEX \"pageview_session_id_idx\" ON \"pageview\"(\"session_id\");\n \n -- CreateIndex\n CREATE INDEX \"pageview_website_id_created_at_idx\" ON \"pageview\"(\"website_id\", \"created_at\");\n \n -- CreateIndex\n CREATE INDEX \"pageview_website_id_idx\" ON \"pageview\"(\"website_id\");\n \n -- CreateIndex\n CREATE INDEX \"pageview_website_id_session_id_created_at_idx\" ON \"pageview\"(\"website_id\", \"session_id\", \"created_at\");\n \n -- CreateIndex\n CREATE UNIQUE INDEX \"session.session_uuid_unique\" ON \"session\"(\"session_uuid\");\n \n -- CreateIndex\n CREATE INDEX \"session_created_at_idx\" ON \"session\"(\"created_at\");\n \n -- CreateIndex\n CREATE INDEX \"session_website_id_idx\" ON \"session\"(\"website_id\");\n \n -- CreateIndex\n CREATE UNIQUE INDEX \"website.website_uuid_unique\" ON \"website\"(\"website_uuid\");\n \n -- CreateIndex\n CREATE UNIQUE INDEX \"website.share_id_unique\" ON \"website\"(\"share_id\");\n \n -- CreateIndex\n CREATE INDEX \"website_user_id_idx\" ON \"website\"(\"user_id\");\n \n -- AddForeignKey\n ALTER TABLE \"event\" ADD FOREIGN KEY (\"session_id\") REFERENCES \"session\"(\"session_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n \n -- AddForeignKey\n ALTER TABLE \"event\" ADD FOREIGN KEY (\"website_id\") REFERENCES \"website\"(\"website_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n \n -- AddForeignKey\n ALTER TABLE \"pageview\" ADD FOREIGN KEY (\"session_id\") REFERENCES \"session\"(\"session_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n \n -- AddForeignKey\n ALTER TABLE \"pageview\" ADD FOREIGN KEY (\"website_id\") REFERENCES \"website\"(\"website_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n \n -- AddForeignKey\n ALTER TABLE \"session\" ADD FOREIGN KEY (\"website_id\") REFERENCES \"website\"(\"website_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n \n -- AddForeignKey\n ALTER TABLE \"website\" ADD FOREIGN KEY (\"user_id\") REFERENCES \"account\"(\"user_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n \n insert into account (username, password, is_admin) values ('admin', '$$hashed$$secret_admin_password', true);"}]}},"variables":[{"id":"$$secret_database_url","name":"DATABASE_URL","label":"Database URL for PostgreSQL","defaultValue":"postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db","description":""},{"id":"$$secret_hash_salt","name":"HASH_SALT","label":"Hash Salt","defaultValue":"$$generate_hex(64)","description":""},{"id":"$$config_database_type","name":"DATABASE_TYPE","label":"Database Type","defaultValue":"postgresql","description":""},{"id":"$$config_postgres_user","name":"POSTGRES_USER","label":"PostgreSQL User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_postgres_password","name":"POSTGRES_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":""},{"id":"$$config_postgres_db","name":"POSTGRES_DB","label":"PostgreSQL Database","defaultValue":"umami","description":""},{"id":"$$secret_admin_password","name":"ADMIN_PASSWORD","label":"Initial Admin Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true}]},{"templateVersion":"1.0.0","ignore":true,"defaultVersion":"postgresql-v1.38.0","documentation":"https://umami.is/docs/getting-started","type":"umami","name":"Umami","subname":"(PostgreSQL)","description":"A simple, easy to use, self-hosted web analytics solution.","services":{"$$id":{"name":"Umami","depends_on":["$$id-postgresql"],"image":"ghcr.io/umami-software/umami:$$core_version","volumes":[],"environment":["ADMIN_PASSWORD=$$secret_admin_password","DATABASE_URL=$$secret_database_url","DATABASE_TYPE=$$config_database_type","HASH_SALT=$$secret_hash_salt"],"ports":["3000"]},"$$id-postgresql":{"name":"PostgreSQL","depends_on":[],"image":"postgres:12-alpine","volumes":["$$id-postgresql-data:/var/lib/postgresql/data"],"environment":["POSTGRES_USER=$$config_postgres_user","POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_DB=$$config_postgres_db"],"ports":[],"files":[{"location":"/docker-entrypoint-initdb.d/schema.postgresql.sql","content":"\n -- CreateTable\n CREATE TABLE \"account\" (\n \"user_id\" SERIAL NOT NULL,\n \"username\" VARCHAR(255) NOT NULL,\n \"password\" VARCHAR(60) NOT NULL,\n \"is_admin\" BOOLEAN NOT NULL DEFAULT false,\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \"updated_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \n PRIMARY KEY (\"user_id\")\n );\n \n -- CreateTable\n CREATE TABLE \"event\" (\n \"event_id\" SERIAL NOT NULL,\n \"website_id\" INTEGER NOT NULL,\n \"session_id\" INTEGER NOT NULL,\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \"url\" VARCHAR(500) NOT NULL,\n \"event_type\" VARCHAR(50) NOT NULL,\n \"event_value\" VARCHAR(50) NOT NULL,\n \n PRIMARY KEY (\"event_id\")\n );\n \n -- CreateTable\n CREATE TABLE \"pageview\" (\n \"view_id\" SERIAL NOT NULL,\n \"website_id\" INTEGER NOT NULL,\n \"session_id\" INTEGER NOT NULL,\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \"url\" VARCHAR(500) NOT NULL,\n \"referrer\" VARCHAR(500),\n \n PRIMARY KEY (\"view_id\")\n );\n \n -- CreateTable\n CREATE TABLE \"session\" (\n \"session_id\" SERIAL NOT NULL,\n \"session_uuid\" UUID NOT NULL,\n \"website_id\" INTEGER NOT NULL,\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \"hostname\" VARCHAR(100),\n \"browser\" VARCHAR(20),\n \"os\" VARCHAR(20),\n \"device\" VARCHAR(20),\n \"screen\" VARCHAR(11),\n \"language\" VARCHAR(35),\n \"country\" CHAR(2),\n \n PRIMARY KEY (\"session_id\")\n );\n \n -- CreateTable\n CREATE TABLE \"website\" (\n \"website_id\" SERIAL NOT NULL,\n \"website_uuid\" UUID NOT NULL,\n \"user_id\" INTEGER NOT NULL,\n \"name\" VARCHAR(100) NOT NULL,\n \"domain\" VARCHAR(500),\n \"share_id\" VARCHAR(64),\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \n PRIMARY KEY (\"website_id\")\n );\n \n -- CreateIndex\n CREATE UNIQUE INDEX \"account.username_unique\" ON \"account\"(\"username\");\n \n -- CreateIndex\n CREATE INDEX \"event_created_at_idx\" ON \"event\"(\"created_at\");\n \n -- CreateIndex\n CREATE INDEX \"event_session_id_idx\" ON \"event\"(\"session_id\");\n \n -- CreateIndex\n CREATE INDEX \"event_website_id_idx\" ON \"event\"(\"website_id\");\n \n -- CreateIndex\n CREATE INDEX \"pageview_created_at_idx\" ON \"pageview\"(\"created_at\");\n \n -- CreateIndex\n CREATE INDEX \"pageview_session_id_idx\" ON \"pageview\"(\"session_id\");\n \n -- CreateIndex\n CREATE INDEX \"pageview_website_id_created_at_idx\" ON \"pageview\"(\"website_id\", \"created_at\");\n \n -- CreateIndex\n CREATE INDEX \"pageview_website_id_idx\" ON \"pageview\"(\"website_id\");\n \n -- CreateIndex\n CREATE INDEX \"pageview_website_id_session_id_created_at_idx\" ON \"pageview\"(\"website_id\", \"session_id\", \"created_at\");\n \n -- CreateIndex\n CREATE UNIQUE INDEX \"session.session_uuid_unique\" ON \"session\"(\"session_uuid\");\n \n -- CreateIndex\n CREATE INDEX \"session_created_at_idx\" ON \"session\"(\"created_at\");\n \n -- CreateIndex\n CREATE INDEX \"session_website_id_idx\" ON \"session\"(\"website_id\");\n \n -- CreateIndex\n CREATE UNIQUE INDEX \"website.website_uuid_unique\" ON \"website\"(\"website_uuid\");\n \n -- CreateIndex\n CREATE UNIQUE INDEX \"website.share_id_unique\" ON \"website\"(\"share_id\");\n \n -- CreateIndex\n CREATE INDEX \"website_user_id_idx\" ON \"website\"(\"user_id\");\n \n -- AddForeignKey\n ALTER TABLE \"event\" ADD FOREIGN KEY (\"session_id\") REFERENCES \"session\"(\"session_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n \n -- AddForeignKey\n ALTER TABLE \"event\" ADD FOREIGN KEY (\"website_id\") REFERENCES \"website\"(\"website_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n \n -- AddForeignKey\n ALTER TABLE \"pageview\" ADD FOREIGN KEY (\"session_id\") REFERENCES \"session\"(\"session_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n \n -- AddForeignKey\n ALTER TABLE \"pageview\" ADD FOREIGN KEY (\"website_id\") REFERENCES \"website\"(\"website_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n \n -- AddForeignKey\n ALTER TABLE \"session\" ADD FOREIGN KEY (\"website_id\") REFERENCES \"website\"(\"website_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n \n -- AddForeignKey\n ALTER TABLE \"website\" ADD FOREIGN KEY (\"user_id\") REFERENCES \"account\"(\"user_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n \n insert into account (username, password, is_admin) values ('admin', '$$hashed$$secret_admin_password', true);"}]}},"variables":[{"id":"$$secret_database_url","name":"DATABASE_URL","label":"Database URL for PostgreSQL","defaultValue":"postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db","description":""},{"id":"$$secret_hash_salt","name":"HASH_SALT","label":"Hash Salt","defaultValue":"$$generate_hex(64)","description":""},{"id":"$$config_database_type","name":"DATABASE_TYPE","label":"Database Type","defaultValue":"postgresql","description":""},{"id":"$$config_postgres_user","name":"POSTGRES_USER","label":"PostgreSQL User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_postgres_password","name":"POSTGRES_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":""},{"id":"$$config_postgres_db","name":"POSTGRES_DB","label":"PostgreSQL Database","defaultValue":"umami","description":""},{"id":"$$secret_admin_password","name":"ADMIN_PASSWORD","label":"Initial Admin Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true}]},{"templateVersion":"1.0.0","defaultVersion":"v0.29.1","documentation":"https://docs.meilisearch.com/learn/getting_started/quick_start.html","type":"meilisearch","name":"MeiliSearch","description":"A lightning Fast, Ultra Relevant, and Typo-Tolerant Search Engine.","services":{"$$id":{"name":"MeiliSearch","documentation":"https://docs.meilisearch.com/","depends_on":[],"image":"getmeili/meilisearch:$$core_version","volumes":["$$id-datams:/meili_data/data.ms","$$id-data:/meili_data","$$id-snapshot:/snapshot","$$id-dump:/dumps"],"environment":["MEILI_MASTER_KEY=$$secret_meili_master_key"],"ports":["7700"]}},"variables":[{"id":"$$secret_meili_master_key","name":"MEILI_MASTER_KEY","label":"Master Key","defaultValue":"$$generate_hex(64)","description":"","showOnConfiguration":true}]},{"templateVersion":"1.0.0","ignore":true,"defaultVersion":"latest","documentation":"https://docs.ghost.org","arch":"amd64","type":"ghost-mariadb","name":"Ghost","subname":"(MariaDB)","description":"Free and open source blogging platform.","labels":["cms","blog"],"services":{"$$id":{"name":"Ghost","depends_on":["$$id-mariadb"],"image":"bitnami/ghost:$$core_version","volumes":["$$id-ghost:/bitnami/ghost"],"environment":["url=$$config_url","GHOST_HOST=$$config_ghost_host","GHOST_ENABLE_HTTPS=$$config_ghost_enable_https","GHOST_EMAIL=$$config_ghost_email","GHOST_PASSWORD=$$secret_ghost_password","GHOST_DATABASE_HOST=$$config_ghost_database_host","GHOST_DATABASE_USER=$$config_mariadb_user","GHOST_DATABASE_PASSWORD=$$secret_ghost_database_password","GHOST_DATABASE_NAME=$$config_mariadb_database","GHOST_DATABASE_PORT_NUMBER=3306"],"ports":["2368"]},"$$id-mariadb":{"name":"MariaDB","depends_on":[],"image":"bitnami/mariadb:latest","volumes":["$$id-mariadb:/bitnami/mariadb"],"environment":["MARIADB_USER=$$config_mariadb_user","MARIADB_PASSWORD=$$secret_mariadb_password","MARIADB_DATABASE=$$config_mariadb_database","MARIADB_ROOT_USER=$$config_mariadb_root_user","MARIADB_ROOT_PASSWORD=$$secret_mariadb_root_password"],"ports":[]}},"variables":[{"id":"$$config_url","name":"url","label":"URL","defaultValue":"$$generate_fqdn","description":""},{"id":"$$config_ghost_host","name":"GHOST_HOST","label":"Ghost Host","defaultValue":"$$generate_domain","description":""},{"id":"$$config_ghost_enable_https","name":"GHOST_ENABLE_HTTPS","label":"Ghost Enable HTTPS","defaultValue":"no","description":""},{"id":"$$config_ghost_email","name":"GHOST_EMAIL","label":"Ghost Default Email","defaultValue":"admin@example.com","description":""},{"id":"$$secret_ghost_password","name":"GHOST_PASSWORD","label":"Ghost Default Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_ghost_database_host","name":"GHOST_DATABASE_HOST","label":"Ghost Database Host","defaultValue":"$$id-mariadb","description":""},{"id":"$$config_ghost_database_user","name":"GHOST_DATABASE_USER","label":"MariaDB User","defaultValue":"$$config_mariadb_user","description":""},{"id":"$$secret_ghost_database_password","name":"GHOST_DATABASE_PASSWORD","label":"MariaDB Password","defaultValue":"$$secret_mariadb_password","description":""},{"id":"$$config_ghost_database_name","name":"GHOST_DATABASE_NAME","label":"MariaDB Database","defaultValue":"$$config_mariadb_database","description":""},{"id":"$$config_mariadb_user","name":"MARIADB_USER","label":"MariaDB User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_mariadb_password","name":"MARIADB_PASSWORD","label":"MariaDB Password","defaultValue":"$$generate_password","description":""},{"id":"$$config_mariadb_database","name":"MARIADB_DATABASE","label":"MariaDB Database","defaultValue":"ghost","description":""},{"id":"$$config_mariadb_root_user","name":"MARIADB_ROOT_USER","label":"MariaDB Root User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_mariadb_root_password","name":"MARIADB_ROOT_PASSWORD","label":"MariaDB Root Password","defaultValue":"$$generate_password","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"5.22","documentation":"https://docs.ghost.org","type":"ghost-only","name":"Ghost","subname":"(without Database)","description":"Free and open source blogging platform.","services":{"$$id":{"name":"Ghost","image":"ghost:$$core_version","volumes":["$$id-ghost:/var/lib/ghost/content"],"environment":["url=$$config_url","database__client=$$config_database__client","database__connection__host=$$config_database__connection__host","database__connection__user=$$config_database__connection__user","database__connection__password=$$secret_database__connection__password","database__connection__database=$$config_database__connection__database"],"ports":["2368"]}},"variables":[{"id":"$$config_url","name":"url","label":"URL","defaultValue":"$$generate_fqdn","description":""},{"id":"$$config_database__client","name":"database__client","label":"Database Client","defaultValue":"mysql","description":"","required":true},{"id":"$$config_database__connection__host","name":"database__connection__host","label":"Database Host","defaultValue":"","description":"","required":true,"placeholder":"db.coolify.io"},{"id":"$$config_database__connection__user","name":"database__connection__user","label":"Database User","defaultValue":"","description":"","placeholder":"ghost","required":true},{"id":"$$secret_database__connection__password","name":"database__connection__password","label":"Database Password","defaultValue":"","description":"","placeholder":"superSecretP4ssword","showOnConfiguration":true,"required":true},{"id":"$$config_database__connection__database","name":"database__connection__database","label":"Database Name","defaultValue":"","description":"","placeholder":"ghost_db","required":true}]},{"templateVersion":"1.0.0","defaultVersion":"5.22","documentation":"https://docs.ghost.org","type":"ghost-mysql","name":"Ghost","subname":"(MySQL)","description":"Ghost is a free and open source blogging platform.","services":{"$$id":{"name":"Ghost","depends_on":["$$id-mysql"],"image":"ghost:$$core_version","volumes":["$$id-ghost:/var/lib/ghost/content"],"environment":["url=$$config_url","database__client=$$config_database__client","database__connection__host=$$config_database__connection__host","database__connection__user=$$config_mysql_user","database__connection__password=$$secret_mysql_password","database__connection__database=$$config_mysql_database"],"ports":["2368"]},"$$id-mysql":{"name":"MySQL","depends_on":[],"image":"mysql:8.0","volumes":["$$id-mysql:/var/lib/mysql"],"environment":["MYSQL_USER=$$config_mysql_user","MYSQL_PASSWORD=$$secret_mysql_password","MYSQL_DATABASE=$$config_mysql_database","MYSQL_ROOT_PASSWORD=$$secret_mysql_root_password"],"ports":[]}},"variables":[{"id":"$$config_url","name":"url","label":"URL","defaultValue":"$$generate_fqdn","description":""},{"id":"$$config_database__client","name":"database__client","label":"Database Client","defaultValue":"mysql","description":"","readOnly":true},{"id":"$$config_database__connection__host","name":"database__connection__host","label":"Database Host","defaultValue":"$$id-mysql","description":""},{"id":"$$config_mysql_user","main":"$$id-mysql","name":"MYSQL_USER","label":"MySQL User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_mysql_password","main":"$$id-mysql","name":"MYSQL_PASSWORD","label":"MySQL Password","defaultValue":"$$generate_password","description":""},{"id":"$$config_mysql_database","main":"$$id-mysql","name":"MYSQL_DATABASE","label":"MySQL Database","defaultValue":"ghost","description":""},{"id":"$$secret_mysql_root_password","name":"MYSQL_ROOT_PASSWORD","label":"MySQL Root Password","defaultValue":"$$generate_password","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"php8.1","documentation":"https://wordpress.org/","type":"wordpress","name":"WordPress","subname":"(MySQL)","description":"A content management system based on PHP.","labels":["wordpress","php","cms"],"services":{"$$id":{"name":"WordPress","depends_on":["$$id-mysql"],"image":"wordpress:$$core_version","volumes":["$$id-wordpress-data:/var/www/html"],"environment":["WORDPRESS_DB_HOST=$$config_wordpress_db_host","WORDPRESS_DB_USER=$$config_mysql_user","WORDPRESS_DB_PASSWORD=$$secret_mysql_password","WORDPRESS_DB_NAME=$$config_mysql_database","WORDPRESS_CONFIG_EXTRA=$$config_wordpress_config_extra"],"ports":["80"]},"$$id-mysql":{"name":"MySQL","depends_on":[],"image":"bitnami/mysql:5.7","imageArm":"mysql:8.0","volumes":["$$id-mysql-data:/bitnami/mysql/data"],"volumesArm":["$$id-mysql-data:/var/lib/mysql"],"environment":["MYSQL_ROOT_PASSWORD=$$secret_mysql_root_password","MYSQL_ROOT_USER=$$config_mysql_root_user","MYSQL_DATABASE=$$config_mysql_database","MYSQL_USER=$$config_mysql_user","MYSQL_PASSWORD=$$secret_mysql_password"]}},"variables":[{"id":"$$config_wordpress_db_host","name":"WORDPRESS_DB_HOST","label":"Database Host","defaultValue":"$$id-mysql","description":"","readOnly":true},{"id":"$$config_wordpress_config_extra","name":"WORDPRESS_CONFIG_EXTRA","label":"WordPress Config Extra","defaultValue":"","description":"","type":"textarea","placeholder":"define('WP_DEBUG', true);\ndefine('WP_DEBUG_LOG', true);\ndefine('WP_DEBUG_DISPLAY', false);\n@ini_set('display_errors', 0);\n"},{"id":"$$secret_mysql_root_password","name":"MYSQL_ROOT_PASSWORD","label":"MySQL Root Password","defaultValue":"$$generate_password","description":"","readOnly":true},{"id":"$$config_mysql_root_user","name":"MYSQL_ROOT_USER","label":"MySQL Root User","defaultValue":"$$generate_username","description":"","readOnly":true},{"id":"$$config_mysql_database","name":"MYSQL_DATABASE","label":"MySQL Database","defaultValue":"wordpress","description":"","readOnly":true},{"id":"$$config_mysql_user","name":"MYSQL_USER","label":"MySQL User","defaultValue":"$$generate_username","description":"","readOnly":true},{"id":"$$secret_mysql_password","name":"MYSQL_PASSWORD","label":"MySQL Password","defaultValue":"$$generate_password","description":"","readOnly":true}]},{"templateVersion":"1.0.0","defaultVersion":"php8.1","documentation":"https://wordpress.org/","type":"wordpress-only","name":"WordPress","subname":"(without DB)","description":"A content management system based on PHP.","labels":["wordpress","php","cms"],"services":{"$$id":{"name":"WordPress","image":"wordpress:$$core_version","volumes":["$$id-wordpress-data:/var/www/html"],"environment":["WORDPRESS_DB_HOST=$$config_wordpress_db_host","WORDPRESS_DB_PORT=$$config_wordpress_db_port","WORDPRESS_DB_USER=$$config_wordpress_db_user","WORDPRESS_DB_PASSWORD=$$secret_wordpress_db_password","WORDPRESS_DB_NAME=$$config_wordpress_db_name","WORDPRESS_CONFIG_EXTRA=$$config_wordpress_config_extra"],"ports":["80"]}},"variables":[{"id":"$$config_wordpress_db_host","name":"WORDPRESS_DB_HOST","label":"Database Host","defaultValue":"","description":"","placeholder":"db.coollabs.io","required":true},{"id":"$$config_wordpress_db_port","name":"WORDPRESS_DB_PORT","label":"Database Port","defaultValue":"","description":"","placeholder":"3306","required":true},{"id":"$$config_wordpress_db_user","name":"WORDPRESS_DB_USER","label":"Database User","defaultValue":"","description":"","placeholder":"wordpress","required":true},{"id":"$$secret_wordpress_db_password","name":"WORDPRESS_DB_PASSWORD","label":"Database Password","defaultValue":"","description":"","placeholder":"supers3cr3tpassw0rd!","required":true,"showOnConfiguration":true},{"id":"$$config_wordpress_db_name","name":"WORDPRESS_DB_NAME","label":"Database Name","defaultValue":"","description":"","placeholder":"wordpress","required":true},{"id":"$$config_wordpress_config_extra","name":"WORDPRESS_CONFIG_EXTRA","label":"Extra Config","defaultValue":"","description":"","type":"textarea","placeholder":"define('WP_DEBUG', true);\ndefine('WP_DEBUG_LOG', true);\ndefine('WP_DEBUG_DISPLAY', false);\n@ini_set('display_errors', 0);\n"}]},{"templateVersion":"1.0.0","defaultVersion":"4.7.1","documentation":"https://coder.com/docs/coder-oss/latest","type":"vscodeserver","name":"VSCode Server","description":"Visual Studio Code on a remote server, accessible through the browser.","labels":["vscode","ide"],"services":{"$$id":{"name":"VSCode Server","depends_on":[],"image":"codercom/code-server:$$core_version","volumes":["$$id-config-data:/home/coder/.local/share/code-server","$$id-vscodeserver-data:/home/coder","$$id-keys-directory:/root/.ssh","$$id-theme-and-plugin-directory:/root/.local/share/code-server"],"environment":["PASSWORD=$$secret_password"],"ports":["8080"]}},"variables":[{"id":"$$secret_password","name":"PASSWORD","label":"Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true}]},{"templateVersion":"1.0.0","defaultVersion":"RELEASE.2022-10-15T19-57-03Z","documentation":"https://min.io/docs/minio","type":"minio","name":"MinIO","description":"A cloud storage server compatible with Amazon S3.","labels":["storage","s3"],"services":{"$$id":{"name":"MinIO","command":"server /data --console-address :9001","depends_on":[],"image":"minio/minio:$$core_version","volumes":["$$id-minio-data:/data","$$id-data-write:/files"],"environment":["MINIO_SERVER_URL=$$config_coolify_fqdn_minio_console","MINIO_BROWSER_REDIRECT_URL=$$config_minio_browser_redirect_url","MINIO_DOMAIN=$$config_minio_domain","MINIO_ROOT_USER=$$config_minio_root_user","MINIO_ROOT_PASSWORD=$$secret_minio_root_password"],"ports":["9000","9001"],"proxy":[{"port":"9000","domain":"$$config_coolify_fqdn_minio_console"},{"port":"9001"}]}},"variables":[{"id":"$$config_coolify_fqdn_minio_console","name":"MINIO_SERVER_URL","label":"MinIO Server URL","defaultValue":"","description":"Specify the URL hostname the MinIO Console should use for connecting to the MinIO Server.","required":true},{"id":"$$config_minio_browser_redirect_url","name":"MINIO_BROWSER_REDIRECT_URL","label":"Browser Redirect URL","defaultValue":"$$generate_fqdn","description":""},{"id":"$$config_minio_domain","name":"MINIO_DOMAIN","label":"Domain","defaultValue":"$$generate_domain","description":""},{"id":"$$config_minio_root_user","name":"MINIO_ROOT_USER","label":"Root User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_minio_root_password","name":"MINIO_ROOT_PASSWORD","label":"Root User Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true}]},{"templateVersion":"1.0.0","defaultVersion":"0.21.1","documentation":"https://fider.io/docs","type":"fider","name":"Fider","description":"A platform to collect and organize customer feedback.","labels":["suggestion","feedback"],"services":{"$$id":{"name":"Fider","image":"getfider/fider:$$core_version","depends_on":["$$id-postgresql"],"environment":["BASE_URL=$$config_base_url","DATABASE_URL=$$secret_database_url","JWT_SECRET=$$secret_jwt_secret","EMAIL_NOREPLY=$$config_email_noreply","EMAIL_MAILGUN_API=$$secret_email_mailgun_api","EMAIL_MAILGUN_REGION=$$config_email_mailgun_region","EMAIL_MAILGUN_DOMAIN=$$config_email_mailgun_domain","EMAIL_SMTP_HOST=$$config_email_smtp_host","EMAIL_SMTP_PORT=$$config_email_smtp_port","EMAIL_SMTP_USER=$$config_email_smtp_user","EMAIL_SMTP_PASSWORD=$$secret_email_smtp_password","EMAIL_SMTP_ENABLE_STARTTLS=$$config_email_smtp_enable_starttls"],"ports":["3000"]},"$$id-postgresql":{"name":"PostgreSQL","depends_on":[],"image":"postgres:12-alpine","volumes":["$$id-postgresql-data:/var/lib/postgresql/data"],"environment":["POSTGRES_USER=$$config_postgres_user","POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_DB=$$config_postgres_db"]}},"variables":[{"id":"$$config_base_url","name":"BASE_URL","label":"Base URL","defaultValue":"$$generate_fqdn","description":""},{"id":"$$secret_database_url","name":"DATABASE_URL","label":"Database URL for PostgreSQL","defaultValue":"postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db?sslmode=disable","description":""},{"id":"$$secret_jwt_secret","name":"JWT_SECRET","label":"JWT Secret","defaultValue":"$$generate_hex(64)","description":""},{"id":"$$config_email_noreply","name":"EMAIL_NOREPLY","label":"No Reply Email Address","defaultValue":"noreply@example.com","description":""},{"id":"$$secret_email_mailgun_api","name":"EMAIL_MAILGUN_API","label":"Mailgun API Key","defaultValue":"","description":"","showOnConfiguration":true},{"id":"$$config_email_mailgun_region","name":"EMAIL_MAILGUN_REGION","label":"Mailgun Region","defaultValue":"EU","description":""},{"id":"$$config_email_mailgun_domain","name":"EMAIL_MAILGUN_DOMAIN","label":"Mailgun Domain","defaultValue":"","description":""},{"id":"$$config_email_smtp_host","name":"EMAIL_SMTP_HOST","label":"SMTP Host","defaultValue":"","description":""},{"id":"$$config_email_smtp_port","name":"EMAIL_SMTP_PORT","label":"SMTP Port","defaultValue":"587","description":""},{"id":"$$config_email_smtp_user","name":"EMAIL_SMTP_USER","label":"SMTP User","defaultValue":"","description":""},{"id":"$$secret_email_smtp_password","name":"EMAIL_SMTP_PASSWORD","label":"SMTP Password","defaultValue":"","description":"","showOnConfiguration":true},{"id":"$$config_email_smtp_enable_starttls","name":"EMAIL_SMTP_ENABLE_STARTTLS","label":"SMTP Enable StartTLS","defaultValue":"false","description":""},{"id":"$$config_postgres_user","name":"POSTGRES_USER","label":"PostgreSQL User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_postgres_password","name":"POSTGRES_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":""},{"id":"$$config_postgres_db","name":"POSTGRES_DB","label":"PostgreSQL Database","defaultValue":"$$generate_username","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"0.198.1","documentation":"https://docs.n8n.io","type":"n8n","name":"n8n.io","description":"A free and open node based Workflow Automation Tool.","labels":["workflow","automation","ifttt","zapier","nodered"],"services":{"$$id":{"name":"N8n","depends_on":[],"image":"n8nio/n8n:$$core_version","volumes":["$$id-data:/root/.n8n","$$id-data-write:/files","/var/run/docker.sock:/var/run/docker.sock"],"environment":["WEBHOOK_URL=$$config_webhook_url"],"ports":["5678"]}},"variables":[{"id":"$$config_webhook_url","name":"WEBHOOK_URL","label":"Webhook URL","defaultValue":"$$generate_fqdn","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"stable","documentation":"https://plausible.io/doc/","arch":"amd64","type":"plausibleanalytics","name":"Plausible Analytics","description":"A lightweight and open-source website analytics tool.","labels":["analytics","statistics","plausible","gdpr","no-cookie","google analytics"],"services":{"$$id":{"name":"Plausible Analytics","command":"sh -c \"sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh db init-admin && /entrypoint.sh run\"","depends_on":["$$id-postgresql","$$id-clickhouse"],"image":"plausible/analytics:$$core_version","environment":["ADMIN_USER_EMAIL=$$config_admin_user_email","ADMIN_USER_NAME=$$config_admin_user_name","ADMIN_USER_PWD=$$secret_admin_user_pwd","BASE_URL=$$config_base_url","SECRET_KEY_BASE=$$secret_secret_key_base","DISABLE_AUTH=$$config_disable_auth","DISABLE_REGISTRATION=$$config_disable_registration","DATABASE_URL=$$secret_database_url","CLICKHOUSE_DATABASE_URL=$$secret_clickhouse_database_url"],"ports":["8000"]},"$$id-postgresql":{"name":"PostgreSQL","image":"bitnami/postgresql:13","volumes":["$$id-postgresql-data:/bitnami/postgresql"],"environment":["POSTGRESQL_PASSWORD=$$secret_postgresql_password","POSTGRESQL_USERNAME=$$config_postgresql_username","POSTGRESQL_DATABASE=$$config_postgresql_database"]},"$$id-clickhouse":{"name":"Clickhouse","volumes":["$$id-clickhouse-data:/var/lib/clickhouse"],"image":"clickhouse/clickhouse-server:22.6-alpine","ulimits":{"nofile":{"soft":262144,"hard":262144}},"files":[{"location":"/etc/clickhouse-server/users.d/logging.xml","content":"warningtrue"},{"location":"/etc/clickhouse-server/config.d/logging.xml","content":"00"},{"location":"/docker-entrypoint-initdb.d/init.query","content":"CREATE DATABASE IF NOT EXISTS plausible;"},{"location":"/docker-entrypoint-initdb.d/init-db.sh","content":"clickhouse client --queries-file /docker-entrypoint-initdb.d/init.query"}]}},"variables":[{"id":"$$config_base_url","name":"BASE_URL","label":"Base URL","defaultValue":"$$generate_fqdn","description":"You must set this to the FQDN of the Plausible Analytics instance. This is used to generate the links to the Plausible Analytics instance."},{"id":"$$secret_database_url","name":"DATABASE_URL","label":"Database URL for PostgreSQL","defaultValue":"postgresql://$$config_postgresql_username:$$secret_postgresql_password@$$id-postgresql:5432/$$config_postgresql_database","description":""},{"id":"$$secret_clickhouse_database_url","name":"CLICKHOUSE_DATABASE_URL","label":"Database URL for Clickhouse","defaultValue":"http://$$id-clickhouse:8123/plausible","description":""},{"id":"$$config_admin_user_email","name":"ADMIN_USER_EMAIL","label":"Admin Email Address","defaultValue":"admin@example.com","description":"This is the admin email. Please change it."},{"id":"$$config_admin_user_name","name":"ADMIN_USER_NAME","label":"Admin User Name","defaultValue":"$$generate_username","description":"This is the admin username. Please change it."},{"id":"$$secret_admin_user_pwd","name":"ADMIN_USER_PWD","label":"Admin User Password","defaultValue":"$$generate_password","description":"This is the admin password. Please change it.","showOnConfiguration":true},{"id":"$$secret_secret_key_base","name":"SECRET_KEY_BASE","label":"Secret Key Base","defaultValue":"$$generate_hex(64)","description":""},{"id":"$$config_disable_auth","name":"DISABLE_AUTH","label":"Disable Authentication","defaultValue":"false","description":""},{"id":"$$config_disable_registration","name":"DISABLE_REGISTRATION","label":"Disable Registration","defaultValue":"true","description":""},{"id":"$$config_postgresql_username","main":"$$id-postgresql","name":"POSTGRESQL_USERNAME","label":"PostgreSQL Username","defaultValue":"postgresql","description":""},{"id":"$$secret_postgresql_password","main":"$$id-postgresql","name":"POSTGRESQL_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_postgresql_database","main":"$$id-postgresql","name":"POSTGRESQL_DATABASE","label":"PostgreSQL Database","defaultValue":"plausible","description":""},{"id":"$$config_scriptName","name":"SCRIPT_NAME","label":"Custom Script Name","defaultValue":"plausible.js","description":"This is the default script name."}]},{"templateVersion":"1.0.0","defaultVersion":"0.98.1","documentation":"https://docs.nocodb.com","type":"nocodb","name":"NocoDB","description":"Turns any MySQL, PostgreSQL, SQL Server, SQLite & MariaDB into a smart-spreadsheet.","labels":["database","airtable","spreadsheet"],"services":{"$$id":{"name":"NocoDB","image":"nocodb/nocodb:$$core_version","environment":["PORT=$$config_port","NC_DB=$$config_nc_db","DATABASE_URL=$$secret_database_url","NC_PUBLIC_URL=$$config_public_url","NC_AUTH_JWT_SECRET=$$secret_auth_jwt_secret","NC_SENTRY_DSN=$$secret_sentry_dsn","NC_CONNECT_TO_EXTERNAL_DB_DISABLED=$$config_connect_to_external_db_disabled","NC_DISABLE_TELE=$$config_disable_tele"],"volumes":["$$id-data:/usr/app/data"],"ports":["8080"]}},"variables":[{"id":"$$config_nc_db","name":"NC_DB","label":"Database","defaultValue":"","description":"MySQL, PostgreSQL and MSSQL connection urls supported. If absent: A local SQLite will be created in root folder."},{"id":"$$config_port","name":"PORT","label":"Port","defaultValue":"8080","description":""},{"id":"$$secret_database_url","name":"DATABASE_URL","label":"Database URL","defaultValue":"","description":"JDBC URL Format. Can be used instead of NC_DB. Used in 1-Click Heroku deployment."},{"id":"$$config_public_url","name":"NC_PUBLIC_URL","label":"Public URL","defaultValue":"","description":"Used for sending Email invitations. If absent: Best guess from http request params."},{"id":"$$secret_auth_jwt_secret","name":"NC_AUTH_JWT_SECRET","label":"Auth JWT Secret","defaultValue":"$$generate_hex(64)","description":"JWT secret used for auth and storing other secrets. If absent: A Random secret will be generated."},{"id":"$$secret_sentry_dsn","name":"NC_SENTRY_DSN","label":"Sentry DSN","defaultValue":"","description":"For Sentry monitoring."},{"id":"$$config_connect_to_external_db_disabled","name":"NC_CONNECT_TO_EXTERNAL_DB_DISABLED","label":"Disable External Database","defaultValue":"0","description":"Disable Project creation with external database. (Enter \"1\" to disable)."},{"id":"$$config_disable_tele","name":"NC_DISABLE_TELE","label":"NocoDB Disable Telemetry","defaultValue":"1","description":"Disable telemetry (Enter \"1\" to disable)."}]}]
\ No newline at end of file
diff --git a/package.json b/package.json
index c2c5bc9d5..d1a77ef05 100644
--- a/package.json
+++ b/package.json
@@ -8,8 +8,10 @@
"oc": "opencollective-setup",
"translate": "pnpm run --filter i18n-converter translate",
"db:studio": "pnpm run --filter api db:studio",
+ "db:studio:trpc": "pnpm run --filter server db:studio",
"db:studio:container": "docker exec coolify pnpm run --filter api db:studio",
"db:push": "pnpm run --filter api db:push",
+ "db:push:trpc": "pnpm run --filter server db:push",
"db:seed": "pnpm run --filter api db:seed",
"db:migrate": "pnpm run --filter api db:migrate",
"db:migrate:container": "docker exec coolify pnpm run --filter api db:migrate",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1c06d02dd..4482f8b63 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -163,9 +163,12 @@ importers:
'@typescript-eslint/eslint-plugin': 5.44.0
'@typescript-eslint/parser': 5.44.0
autoprefixer: 10.4.13
+ cuid: 2.1.8
+ daisyui: 2.41.0
eslint: 8.28.0
eslint-config-prettier: 8.5.0
eslint-plugin-svelte3: 4.0.0
+ flowbite-svelte: 0.28.0
js-cookie: 3.0.1
postcss: 8.4.19
postcss-load-config: 4.0.1
@@ -183,6 +186,9 @@ importers:
dependencies:
'@trpc/client': 10.1.0_@trpc+server@10.1.0
'@trpc/server': 10.1.0
+ cuid: 2.1.8
+ daisyui: 2.41.0_2lwn2upnx27dqeg6hqdu7sq75m
+ flowbite-svelte: 0.28.0
js-cookie: 3.0.1
server: link:../server
superjson: 1.11.0
@@ -231,22 +237,34 @@ importers:
'@prisma/client': 4.6.1
'@trpc/client': 10.1.0
'@trpc/server': 10.1.0
+ '@types/jsonwebtoken': ^8.5.9
'@types/node': 18.11.9
'@types/node-fetch': 2.6.2
+ '@types/shell-quote': ^1.7.1
'@types/ws': 8.5.3
abort-controller: 3.0.0
+ bcryptjs: 2.4.3
+ cuid: 2.1.8
+ dayjs: 1.11.6
+ dotenv: ^16.0.3
+ execa: 6.1.0
fastify: 4.10.2
fastify-plugin: 4.4.0
+ got: ^12.5.3
+ is-port-reachable: 4.0.0
jsonwebtoken: 8.5.1
node-fetch: 3.3.0
npm-run-all: 4.1.5
prisma: 4.6.1
rimraf: 3.0.2
+ shell-quote: ^1.7.4
+ ssh-config: 4.1.6
start-server-and-test: 1.14.0
superjson: 1.11.0
tslib: 2.4.1
tsx: 3.12.1
typescript: 4.9.3
+ unique-names-generator: 4.7.1
wait-port: 1.0.4
ws: 8.11.0
zod: 3.19.1
@@ -261,18 +279,30 @@ importers:
'@trpc/client': 10.1.0_@trpc+server@10.1.0
'@trpc/server': 10.1.0
abort-controller: 3.0.0
+ bcryptjs: 2.4.3
+ cuid: 2.1.8
+ dayjs: 1.11.6
+ dotenv: 16.0.3
+ execa: 6.1.0
fastify: 4.10.2
fastify-plugin: 4.4.0
+ got: 12.5.3
+ is-port-reachable: 4.0.0
jsonwebtoken: 8.5.1
node-fetch: 3.3.0
prisma: 4.6.1
+ shell-quote: 1.7.4
+ ssh-config: 4.1.6
superjson: 1.11.0
tslib: 2.4.1
+ unique-names-generator: 4.7.1
ws: 8.11.0
zod: 3.19.1
devDependencies:
+ '@types/jsonwebtoken': 8.5.9
'@types/node': 18.11.9
'@types/node-fetch': 2.6.2
+ '@types/shell-quote': 1.7.1
'@types/ws': 8.5.3
npm-run-all: 4.1.5
rimraf: 3.0.2
@@ -1716,7 +1746,6 @@ packages:
/@popperjs/core/2.11.6:
resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==}
- dev: true
/@prisma/client/4.6.1_prisma@4.6.1:
resolution: {integrity: sha512-M1+NNrMzqaOIxT7PBGcTs3IZo7d1EW/+gVQd4C4gUgWBDGgD9AcIeZnUSidgWClmpMSgVUdnVORjsWWGUameYA==}
@@ -2040,6 +2069,12 @@ packages:
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
dev: true
+ /@types/jsonwebtoken/8.5.9:
+ resolution: {integrity: sha512-272FMnFGzAVMGtu9tkr29hRL6bZj4Zs1KZNeHLnKqAvp06tAIcarTMwOh8/8bz4FmKRcMxZhZNeUAQsNLoiPhg==}
+ dependencies:
+ '@types/node': 18.11.9
+ dev: true
+
/@types/keyv/3.1.4:
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
dependencies:
@@ -2100,6 +2135,10 @@ packages:
resolution: {integrity: sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==}
dev: true
+ /@types/shell-quote/1.7.1:
+ resolution: {integrity: sha512-SWZ2Nom1pkyXCDohRSrkSKvDh8QOG9RfAsrt5/NsPQC4UQJ55eG0qClA40I+Gkez4KTQ0uDUT8ELRXThf3J5jw==}
+ dev: true
+
/@types/which/2.0.1:
resolution: {integrity: sha512-Jjakcv8Roqtio6w1gr0D7y6twbhx6gGgFGF5BLwajPpnOIOxFkakFhCq+LmyyeAz7BX6ULrjBOxdKaCDy+4+dQ==}
dev: false
@@ -3454,7 +3493,6 @@ packages:
/classnames/2.3.2:
resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==}
- dev: true
/clean-stack/4.2.0:
resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==}
@@ -4801,14 +4839,12 @@ packages:
'@popperjs/core': 2.11.6
classnames: 2.3.2
flowbite: 1.5.4
- dev: true
/flowbite/1.5.4:
resolution: {integrity: sha512-A4VTeJE+aHSbwrMzWvpTADhNgX8Njpb3DqRL26pFkOupklPg8cmNstZK8cXrFnBPxomOiX/OazZnhQM1BIZADQ==}
dependencies:
'@popperjs/core': 2.11.6
mini-svg-data-uri: 1.4.4
- dev: true
/follow-redirects/1.15.2_debug@4.3.2:
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
@@ -5997,7 +6033,6 @@ packages:
/mini-svg-data-uri/1.4.4:
resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
hasBin: true
- dev: true
/minimalistic-assert/1.0.1:
resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}