Compare commits

...

21 Commits

Author SHA1 Message Date
Henry
09a190d6fb feat: add debug logs to sendEmail 2025-06-19 21:54:24 +01:00
Henry
5586c26c12 fix: use default output mode for next 2025-06-18 23:18:12 +01:00
Henry
2d7097eb83 chore: cleanup test dockerfile 2025-06-18 23:11:29 +01:00
Henry
2aa898da00 feat: enable starting in standalone mode 2025-06-18 22:57:12 +01:00
Henry
a01a826bac fix: build with env vars 2025-06-18 22:49:09 +01:00
Henry
a29ea76024 fix: update build context in compose 2025-06-18 22:34:13 +01:00
Henry
e1c6bfd6cd fix: add test compose file for cloud 2025-06-18 22:27:46 +01:00
Henry
c272c38f6b feat: reduce docker image size by using next standalone output (#89) 2025-06-18 22:16:50 +01:00
khalt00
02d3d300fb change volume name (#88)
Co-authored-by: Le Trong Kha <kha.le@ao360.com.vn>
2025-06-17 23:20:15 +01:00
Henry
0bd28f9f95 fix: set container name env var 2025-06-17 23:02:24 +01:00
Henry
d0c2314ebf feat: add posthog analytics 2025-06-17 22:45:06 +01:00
Henry
268871c348 fix: bump compose 2025-06-17 11:00:28 +01:00
Henry
2e11199764 fix: add old docker compose and revert entrypoint 2025-06-17 10:57:54 +01:00
Henry
fc6bb22400 fix: copy static files and use explicit shell in Docker (#86) (#87)
* fix: copy static files to standalone dir

* fix: update Dockerfile to use /bin/sh for entrypoint execution

* fix: update Dockerfile to copy static files from apps/web directory

* fix: copy from root

* fix: set workdir

* fix: copy files from inside the container

* fix: add logs to debug

* fix: remove workdir

* fix: log contents of build

* fix: copy static files

* fix: remove log

* chore: remove spacing
2025-06-16 22:50:21 +01:00
Henry
1c75a948f9 feat: setup postgres with docker compose (#85)
* feat: add postgres to docker compose

* feat: run migrations via entrypoint

* chore: tidy .env.example

* fix: allow empty strings for optional envs

* fix: remove external from kan-network

* chore: update readme
2025-06-14 22:52:27 +01:00
Henry
3a48c797b7 feat: set web port with env variable 2025-06-13 22:03:57 +01:00
Henry
b838e8040a fix: remove version from docker compose (#81) 2025-06-13 21:43:05 +01:00
Henry
f0e3c4c3e2 fix: render comments inside contenteditable (#79) 2025-06-13 09:23:55 +01:00
Henry
d6b0b5cd80 Revert "chore: optimize Docker build with multi-stage process and add standalone Next.js output (#75)"s
This reverts commit 1707557bea.
2025-06-12 22:26:59 +01:00
LovelessCodes
1707557bea chore: optimize Docker build with multi-stage process and add standalone Next.js output (#75) 2025-06-12 22:12:24 +01:00
Henry
f6114a56af chore: patch migration order (#74) 2025-06-10 21:15:47 +01:00
19 changed files with 2671 additions and 723 deletions

View File

@@ -1,28 +1,39 @@
POSTGRES_URL= # https://github.com/kanbn/kan?tab=readme-ov-file#environment-variables-)
EMAIL_FROM= # Required environment variables
NEXT_PUBLIC_BASE_URL= # e.g. https://kan.bn
BETTER_AUTH_SECRET= # Random 32+ char string (can gen with: openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 32)
POSTGRES_URL= # e.g. postgresql://kan:your_password@your_host:5432/kan
# Only required if deploying from compose
POSTGRES_PASSWORD=
# SMTP (optional)
SMTP_HOST= SMTP_HOST=
SMTP_PORT= SMTP_PORT=465 # Port 587 will not work
SMTP_USER= SMTP_USER=
SMTP_PASSWORD= SMTP_PASSWORD=
EMAIL_FROM= # e.g. "Kan <hello@mail.kan.bn>"
NEXT_PUBLIC_BASE_URL= # S3 storage (optional)
NEXT_PUBLIC_STORAGE_URL=
NEXT_PUBLIC_AVATAR_BUCKET_NAME=
NEXT_PUBLIC_ALLOW_CREDENTIALS=
NEXT_PUBLIC_DISABLE_SIGN_UP=
S3_REGION= S3_REGION=
S3_ENDPOINT= S3_ENDPOINT=
S3_ACCESS_KEY_ID= S3_ACCESS_KEY_ID=
S3_SECRET_ACCESS_KEY= S3_SECRET_ACCESS_KEY=
NEXT_PUBLIC_STORAGE_URL=
NEXT_PUBLIC_AVATAR_BUCKET_NAME=
NEXT_PUBLIC_STORAGE_DOMAIN=
BETTER_AUTH_SECRET= # Auth config (optional)
BETTER_AUTH_TRUSTED_ORIGINS= NEXT_PUBLIC_ALLOW_CREDENTIALS=
NEXT_PUBLIC_DISABLE_SIGN_UP=
# Integration providers (optional)
TRELLO_APP_API_KEY= TRELLO_APP_API_KEY=
TRELLO_APP_SECRET= TRELLO_APP_SECRET=
# OAuth providers (optional)
BETTER_AUTH_TRUSTED_ORIGINS=
GOOGLE_CLIENT_ID= GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET= GOOGLE_CLIENT_SECRET=
DISCORD_CLIENT_ID= DISCORD_CLIENT_ID=

View File

@@ -47,34 +47,67 @@ See our [roadmap](https://kan.bn/kan/roadmap) for upcoming features.
## Self Hosting 🐳 ## Self Hosting 🐳
### PostgreSQL Database Setup The easiest way to self-host Kan is with Docker Compose. This will set up everything for you including your postgres database.
Kan requires a PostgreSQL database. You can run one using the official PostgreSQL Docker image: 1. Create a new file called `docker-compose.yml` and paste the following configuration:
```bash ```yaml
# Run PostgreSQL in a container using the official postgres image services:
docker run -d \ web:
--name kan-db \ image: ghcr.io/kanbn/kan:latest
-e POSTGRES_DB=kan \ container_name: kan-web
-e POSTGRES_USER=kan_user \ ports:
-e POSTGRES_PASSWORD=your_secure_password \ - "3000:3000"
-p 5432:5432 \ networks:
-v kan_postgres_data:/var/lib/postgresql/data \ - kan-network
postgres:15 environment:
NEXT_PUBLIC_BASE_URL: http://localhost:3000
BETTER_AUTH_SECRET: your_auth_secret
POSTGRES_URL: postgresql://kan:your_postgres_password@postgres:5432/kan_db
NEXT_PUBLIC_ALLOW_CREDENTIALS: true
depends_on:
- postgres
restart: unless-stopped
# Your POSTGRES_URL should be: postgres:
# postgres://kan_user:your_secure_password@your_host:5432/kan image: postgres:15
container_name: kan-db
environment:
POSTGRES_DB: kan_db
POSTGRES_USER: kan
POSTGRES_PASSWORD: your_postgres_password
ports:
- 5432:5432
volumes:
- kan_postgres_data:/var/lib/postgresql/data
restart: unless-stopped
networks:
- kan-network
networks:
kan-network:
volumes:
kan_postgres_data:
``` ```
### Kan Application Deployment 2. Start the containers in detached mode:
Deploy Kan with Docker using our pre-built image:
```bash ```bash
docker pull ghcr.io/kanbn/kan:latest && docker run -it -p 3000:3000 --env-file .env ghcr.io/kanbn/kan:latest docker compose up -d
``` ```
Make sure to create a `.env` file with the required environment variables (see the Environment Variables section below). 3. Access Kan at http://localhost:3000
The application will be running in the background. You can manage the containers using these commands:
- To stop the containers: `docker compose down`
- To view logs: `docker compose logs -f`
- To restart the containers: `docker compose restart`
For the complete Docker Compose configuration, see [docker-compose.yml](./docker-compose.yml) in the repository.
> **Note**: The Docker Compose configuration shown above is a minimal example. For a complete setup with all features (email, OAuth, file uploads, etc.), you'll need to create a `.env` file with the required environment variables. See the Environment Variables section below for the full list of available options.
## Local Development 🧑‍💻 ## Local Development 🧑‍💻

View File

@@ -53,8 +53,14 @@ RUN --mount=type=cache,id=pnpm,target=~/.pnpm-store pnpm install --frozen-lockfi
# Copy source code of isolated subworkspace # Copy source code of isolated subworkspace
COPY --from=pruner /app/out/full/ . COPY --from=pruner /app/out/full/ .
RUN pnpm build --filter=${PROJECT} RUN pnpm build --filter=${PROJECT}
# # Copy static files to standalone directory
# RUN mkdir -p apps/web/.next/standalone/.next && \
# mv apps/web/public apps/web/.next/standalone/ && \
# mv apps/web/.next/static apps/web/.next/standalone/.next/
# 4. Final image - runner stage to run the application # 4. Final image - runner stage to run the application
FROM base AS runner FROM base AS runner
ARG APP_DIRNAME ARG APP_DIRNAME
@@ -75,6 +81,5 @@ ARG PORT=3000
ENV PORT=${PORT} ENV PORT=${PORT}
EXPOSE ${PORT} EXPOSE ${PORT}
# Run migration on start for now (until we have a better way to handle this)
CMD ["sh", "-c", "cd /app && pnpm db:migrate && cd /app/apps/web && pnpm start"] CMD ["sh", "-c", "cd /app && pnpm db:migrate && cd /app/apps/web && pnpm start"]

23
apps/web/entrypoint.sh Normal file
View File

@@ -0,0 +1,23 @@
#!/bin/sh
# Run migrations from the Turborepo root context
echo "Running database migrations..."
# Navigate to the Turborepo root to run the db:migrate command
pnpm --prefix /app db:migrate
# Check if migration was successful
if [ $? -ne 0 ]; then
echo "\nDatabase migration failed! Exiting."
exit 1
fi
echo "\nStarting Next.js application..."
# Check if we should use standalone mode
if [ "$NEXT_PUBLIC_USE_STANDALONE_OUTPUT" = "true" ]; then
echo "Starting in standalone mode..."
exec node .next/standalone/apps/web/server.js
else
echo "Starting in standard mode..."
exec pnpm start
fi

View File

@@ -10,6 +10,10 @@ configureRuntimeEnv();
/** @type {import("next").NextConfig} */ /** @type {import("next").NextConfig} */
const config = { const config = {
output:
env("NEXT_PUBLIC_USE_STANDALONE_OUTPUT") === "true"
? "standalone"
: undefined,
reactStrictMode: true, reactStrictMode: true,
/** Enables hot reloading for local packages without a build step */ /** Enables hot reloading for local packages without a build step */

View File

@@ -4,7 +4,7 @@
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
"build": "pnpm next build", "build": "pnpm with-env next build",
"clean": "git clean -xdf .cache .next .turbo node_modules", "clean": "git clean -xdf .cache .next .turbo node_modules",
"dev": "pnpm with-env next dev | pino-pretty", "dev": "pnpm with-env next dev | pino-pretty",
"format": "prettier --check . --ignore-path ../../.gitignore", "format": "prettier --check . --ignore-path ../../.gitignore",
@@ -42,6 +42,7 @@
"next-runtime-env": "^1.7.2", "next-runtime-env": "^1.7.2",
"nextjs-cors": "^2.2.0", "nextjs-cors": "^2.2.0",
"pino": "^9.6.0", "pino": "^9.6.0",
"posthog-js": "^1.254.0",
"react": "catalog:react18", "react": "catalog:react18",
"react-beautiful-dnd": "^13.1.1", "react-beautiful-dnd": "^13.1.1",
"react-contenteditable": "^3.3.7", "react-contenteditable": "^3.3.7",

View File

@@ -17,8 +17,11 @@ export const env = createEnv({
BETTER_AUTH_SECRET: z.string(), BETTER_AUTH_SECRET: z.string(),
BETTER_AUTH_TRUSTED_ORIGINS: z BETTER_AUTH_TRUSTED_ORIGINS: z
.string() .string()
.refine((s) => .transform((s) => (s === "" ? undefined : s))
s.split(",").every((l) => z.string().url().safeParse(l).success), .refine(
(s) =>
!s ||
s.split(",").every((l) => z.string().url().safeParse(l).success),
) )
.optional(), .optional(),
POSTGRES_URL: z.string().url(), POSTGRES_URL: z.string().url(),
@@ -76,17 +79,26 @@ export const env = createEnv({
client: { client: {
NEXT_PUBLIC_KAN_ENV: z.string().optional(), NEXT_PUBLIC_KAN_ENV: z.string().optional(),
NEXT_PUBLIC_UMAMI_ID: z.string().optional(), NEXT_PUBLIC_UMAMI_ID: z.string().optional(),
NEXT_PUBLIC_POSTHOG_KEY: z.string().optional(),
NEXT_PUBLIC_POSTHOG_HOST: z.string().optional(),
NEXT_PUBLIC_USE_STANDALONE_OUTPUT: z.string().optional(),
NEXT_PUBLIC_BASE_URL: z.string().url(), NEXT_PUBLIC_BASE_URL: z.string().url(),
NEXT_PUBLIC_STORAGE_URL: z.string().url().optional(), NEXT_PUBLIC_STORAGE_URL: z.string().url().optional(),
NEXT_PUBLIC_AVATAR_BUCKET_NAME: z.string().optional(), NEXT_PUBLIC_AVATAR_BUCKET_NAME: z.string().optional(),
NEXT_PUBLIC_STORAGE_DOMAIN: z.string().optional(), NEXT_PUBLIC_STORAGE_DOMAIN: z.string().optional(),
NEXT_PUBLIC_ALLOW_CREDENTIALS: z NEXT_PUBLIC_ALLOW_CREDENTIALS: z
.string() .string()
.refine((s) => s.toLowerCase() === "true" || s.toLowerCase() === "false") .transform((s) => (s === "" ? undefined : s))
.refine(
(s) => !s || s.toLowerCase() === "true" || s.toLowerCase() === "false",
)
.optional(), .optional(),
NEXT_PUBLIC_DISABLE_SIGN_UP: z NEXT_PUBLIC_DISABLE_SIGN_UP: z
.string() .string()
.refine((s) => s.toLowerCase() === "true" || s.toLowerCase() === "false") .transform((s) => (s === "" ? undefined : s))
.refine(
(s) => !s || s.toLowerCase() === "true" || s.toLowerCase() === "false",
)
.optional(), .optional(),
}, },
/** /**
@@ -96,12 +108,16 @@ export const env = createEnv({
NEXT_PUBLIC_KAN_ENV: process.env.NEXT_PUBLIC_KAN_ENV, NEXT_PUBLIC_KAN_ENV: process.env.NEXT_PUBLIC_KAN_ENV,
NODE_ENV: process.env.NODE_ENV, NODE_ENV: process.env.NODE_ENV,
NEXT_PUBLIC_UMAMI_ID: process.env.NEXT_PUBLIC_UMAMI_ID, NEXT_PUBLIC_UMAMI_ID: process.env.NEXT_PUBLIC_UMAMI_ID,
NEXT_PUBLIC_POSTHOG_KEY: process.env.NEXT_PUBLIC_POSTHOG_KEY,
NEXT_PUBLIC_POSTHOG_HOST: process.env.NEXT_PUBLIC_POSTHOG_HOST,
NEXT_PUBLIC_BASE_URL: process.env.NEXT_PUBLIC_BASE_URL, NEXT_PUBLIC_BASE_URL: process.env.NEXT_PUBLIC_BASE_URL,
NEXT_PUBLIC_STORAGE_URL: process.env.NEXT_PUBLIC_STORAGE_URL, NEXT_PUBLIC_STORAGE_URL: process.env.NEXT_PUBLIC_STORAGE_URL,
NEXT_PUBLIC_AVATAR_BUCKET_NAME: process.env.NEXT_PUBLIC_AVATAR_BUCKET_NAME, NEXT_PUBLIC_AVATAR_BUCKET_NAME: process.env.NEXT_PUBLIC_AVATAR_BUCKET_NAME,
NEXT_PUBLIC_STORAGE_DOMAIN: process.env.NEXT_PUBLIC_STORAGE_DOMAIN, NEXT_PUBLIC_STORAGE_DOMAIN: process.env.NEXT_PUBLIC_STORAGE_DOMAIN,
NEXT_PUBLIC_ALLOW_CREDENTIALS: process.env.NEXT_PUBLIC_ALLOW_CREDENTIALS, NEXT_PUBLIC_ALLOW_CREDENTIALS: process.env.NEXT_PUBLIC_ALLOW_CREDENTIALS,
NEXT_PUBLIC_DISABLE_SIGN_UP: process.env.NEXT_PUBLIC_DISABLE_SIGN_UP, NEXT_PUBLIC_DISABLE_SIGN_UP: process.env.NEXT_PUBLIC_DISABLE_SIGN_UP,
NEXT_PUBLIC_USE_STANDALONE_OUTPUT:
process.env.NEXT_PUBLIC_USE_STANDALONE_OUTPUT,
}, },
skipValidation: skipValidation:
!!process.env.CI || process.env.npm_lifecycle_event === "lint", !!process.env.CI || process.env.npm_lifecycle_event === "lint",

View File

@@ -2,7 +2,11 @@ import "~/styles/globals.css";
import type { AppType } from "next/app"; import type { AppType } from "next/app";
import { Plus_Jakarta_Sans } from "next/font/google"; import { Plus_Jakarta_Sans } from "next/font/google";
import Script from "next/script";
import { env } from "next-runtime-env"; import { env } from "next-runtime-env";
import posthog from "posthog-js";
import { PostHogProvider } from "posthog-js/react";
import { useEffect } from "react";
import { ModalProvider } from "~/providers/modal"; import { ModalProvider } from "~/providers/modal";
import { PopupProvider } from "~/providers/popup"; import { PopupProvider } from "~/providers/popup";
@@ -21,6 +25,21 @@ export const metadata = {
}; };
const MyApp: AppType = ({ Component, pageProps }) => { const MyApp: AppType = ({ Component, pageProps }) => {
const posthogKey = env("NEXT_PUBLIC_POSTHOG_KEY");
useEffect(() => {
if (posthogKey) {
posthog.init(posthogKey, {
api_host: env("NEXT_PUBLIC_POSTHOG_HOST"),
person_profiles: "identified_only",
defaults: "2025-05-24",
loaded: (posthog) => {
if (process.env.NODE_ENV === "development") posthog.debug();
},
});
}
}, [posthogKey]);
return ( return (
<> <>
<style jsx global>{` <style jsx global>{`
@@ -32,7 +51,7 @@ const MyApp: AppType = ({ Component, pageProps }) => {
} }
`}</style> `}</style>
{env("NEXT_PUBLIC_UMAMI_ID") && ( {env("NEXT_PUBLIC_UMAMI_ID") && (
<script <Script
defer defer
src="https://cloud.umami.is/script.js" src="https://cloud.umami.is/script.js"
data-website-id={env("NEXT_PUBLIC_UMAMI_ID")} data-website-id={env("NEXT_PUBLIC_UMAMI_ID")}
@@ -43,7 +62,13 @@ const MyApp: AppType = ({ Component, pageProps }) => {
<ThemeProvider> <ThemeProvider>
<ModalProvider> <ModalProvider>
<PopupProvider> <PopupProvider>
<Component {...pageProps} /> {posthogKey ? (
<PostHogProvider client={posthog}>
<Component {...pageProps} />
</PostHogProvider>
) : (
<Component {...pageProps} />
)}
</PopupProvider> </PopupProvider>
</ModalProvider> </ModalProvider>
</ThemeProvider> </ThemeProvider>

View File

@@ -132,7 +132,11 @@ const Comment = ({
)} )}
</div> </div>
{!isEditing ? ( {!isEditing ? (
<p className="mt-2 text-sm">{comment}</p> <ContentEditable
html={comment ?? ""}
disabled={true}
className="mt-2 text-sm"
/>
) : ( ) : (
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
<ContentEditable <ContentEditable

63
cloud/docker-compose.yml Normal file
View File

@@ -0,0 +1,63 @@
services:
web:
image: ghcr.io/kanbn/kan:latest
container_name: ${CONTAINER_NAME:-kan-web}
ports:
- "${WEB_PORT:-3000}:3000"
networks:
- dokploy-network
build:
context: ..
dockerfile: apps/web/Dockerfile
env_file:
- .env
restart: unless-stopped
environment:
- NEXT_PUBLIC_KAN_ENV=${NEXT_PUBLIC_KAN_ENV}
- NEXT_PUBLIC_BASE_URL=${NEXT_PUBLIC_BASE_URL}
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
- POSTGRES_URL=${POSTGRES_URL}
- NEXT_PUBLIC_USE_STANDALONE_OUTPUT=${NEXT_PUBLIC_USE_STANDALONE_OUTPUT}
# Stripe
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
# SMTP
- SMTP_HOST=${SMTP_HOST}
- SMTP_PORT=${SMTP_PORT}
- SMTP_USER=${SMTP_USER}
- SMTP_PASSWORD=${SMTP_PASSWORD}
- EMAIL_FROM=${EMAIL_FROM}
# S3 storage
- S3_ACCESS_KEY_ID=${S3_ACCESS_KEY_ID}
- S3_SECRET_ACCESS_KEY=${S3_SECRET_ACCESS_KEY}
- S3_REGION=${S3_REGION}
- S3_ENDPOINT=${S3_ENDPOINT}
- NEXT_PUBLIC_STORAGE_URL=${NEXT_PUBLIC_STORAGE_URL}
- NEXT_PUBLIC_AVATAR_BUCKET_NAME=${NEXT_PUBLIC_AVATAR_BUCKET_NAME}
- NEXT_PUBLIC_STORAGE_DOMAIN=${NEXT_PUBLIC_STORAGE_DOMAIN}
# Auth config
- NEXT_PUBLIC_ALLOW_CREDENTIALS=${NEXT_PUBLIC_ALLOW_CREDENTIALS}
- NEXT_PUBLIC_DISABLE_SIGN_UP=${NEXT_PUBLIC_DISABLE_SIGN_UP}
# Integration providers
- TRELLO_APP_API_KEY=${TRELLO_APP_API_KEY}
- TRELLO_APP_SECRET=${TRELLO_APP_SECRET}
# OAuth providers (optional)
- BETTER_AUTH_TRUSTED_ORIGINS=${BETTER_AUTH_TRUSTED_ORIGINS}
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
# Analytics
- NEXT_PUBLIC_UMAMI_ID=${NEXT_PUBLIC_UMAMI_ID}
- NEXT_PUBLIC_POSTHOG_KEY=${NEXT_PUBLIC_POSTHOG_KEY}
- NEXT_PUBLIC_POSTHOG_HOST=${NEXT_PUBLIC_POSTHOG_HOST}
networks:
dokploy-network:
external: true
#bump

View File

@@ -1,31 +1,49 @@
version: "3.7"
services: services:
web: web:
image: ghcr.io/kanbn/kan:latest image: ghcr.io/kanbn/kan:latest
container_name: ${CONTAINER_NAME:-kan-web}
ports: ports:
- "3001:3000" - "${WEB_PORT:-3000}:3000"
networks: networks:
- kan-network
- dokploy-network - dokploy-network
build: build:
context: . context: .
dockerfile: ./apps/web/Dockerfile dockerfile: ./apps/web/Dockerfile.new
env_file: env_file:
- .env - .env
command: ["pnpm", "start"]
environment: environment:
- EMAIL_FROM=${EMAIL_FROM} # Required environment variables
- NEXT_PUBLIC_BASE_URL=${NEXT_PUBLIC_BASE_URL}
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
- POSTGRES_URL=${POSTGRES_URL}
# SMTP (optional)
- SMTP_HOST=${SMTP_HOST} - SMTP_HOST=${SMTP_HOST}
- SMTP_PORT=${SMTP_PORT} - SMTP_PORT=${SMTP_PORT}
- SMTP_USER=${SMTP_USER} - SMTP_USER=${SMTP_USER}
- SMTP_PASSWORD=${SMTP_PASSWORD} - SMTP_PASSWORD=${SMTP_PASSWORD}
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET} - EMAIL_FROM=${EMAIL_FROM}
- BETTER_AUTH_TRUSTED_ORIGINS=${BETTER_AUTH_TRUSTED_ORIGINS}
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY} # S3 storage (optional)
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET} - S3_ACCESS_KEY_ID=${S3_ACCESS_KEY_ID}
- POSTGRES_URL=${POSTGRES_URL} - S3_SECRET_ACCESS_KEY=${S3_SECRET_ACCESS_KEY}
- S3_REGION=${S3_REGION}
- S3_ENDPOINT=${S3_ENDPOINT}
- NEXT_PUBLIC_STORAGE_URL=${NEXT_PUBLIC_STORAGE_URL}
- NEXT_PUBLIC_AVATAR_BUCKET_NAME=${NEXT_PUBLIC_AVATAR_BUCKET_NAME}
- NEXT_PUBLIC_STORAGE_DOMAIN=${NEXT_PUBLIC_STORAGE_DOMAIN}
# Auth config (optional)
- NEXT_PUBLIC_ALLOW_CREDENTIALS=${NEXT_PUBLIC_ALLOW_CREDENTIALS}
- NEXT_PUBLIC_DISABLE_SIGN_UP=${NEXT_PUBLIC_DISABLE_SIGN_UP}
# Integration providers (optional)
- TRELLO_APP_API_KEY=${TRELLO_APP_API_KEY} - TRELLO_APP_API_KEY=${TRELLO_APP_API_KEY}
- TRELLO_APP_SECRET=${TRELLO_APP_SECRET} - TRELLO_APP_SECRET=${TRELLO_APP_SECRET}
# OAuth providers (optional)
- BETTER_AUTH_TRUSTED_ORIGINS=${BETTER_AUTH_TRUSTED_ORIGINS}
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID} - GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET} - GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
- DISCORD_CLIENT_ID=${DISCORD_CLIENT_ID} - DISCORD_CLIENT_ID=${DISCORD_CLIENT_ID}
@@ -63,18 +81,37 @@ services:
- APPLE_CLIENT_ID=${APPLE_CLIENT_ID} - APPLE_CLIENT_ID=${APPLE_CLIENT_ID}
- APPLE_CLIENT_SECRET=${APPLE_CLIENT_SECRET} - APPLE_CLIENT_SECRET=${APPLE_CLIENT_SECRET}
- APPLE_APP_BUNDLE_IDENTIFIER=${APPLE_APP_BUNDLE_IDENTIFIER} - APPLE_APP_BUNDLE_IDENTIFIER=${APPLE_APP_BUNDLE_IDENTIFIER}
- S3_ACCESS_KEY_ID=${S3_ACCESS_KEY_ID}
- S3_SECRET_ACCESS_KEY=${S3_SECRET_ACCESS_KEY} # Cloud (not required)
- S3_REGION=${S3_REGION}
- S3_ENDPOINT=${S3_ENDPOINT}
- NEXT_PUBLIC_KAN_ENV=${NEXT_PUBLIC_KAN_ENV} - NEXT_PUBLIC_KAN_ENV=${NEXT_PUBLIC_KAN_ENV}
- NEXT_PUBLIC_BASE_URL=${NEXT_PUBLIC_BASE_URL}
- NEXT_PUBLIC_STORAGE_URL=${NEXT_PUBLIC_STORAGE_URL}
- NEXT_PUBLIC_AVATAR_BUCKET_NAME=${NEXT_PUBLIC_AVATAR_BUCKET_NAME}
- NEXT_PUBLIC_STORAGE_DOMAIN=${NEXT_PUBLIC_STORAGE_DOMAIN}
- NEXT_PUBLIC_UMAMI_ID=${NEXT_PUBLIC_UMAMI_ID} - NEXT_PUBLIC_UMAMI_ID=${NEXT_PUBLIC_UMAMI_ID}
- NEXT_PUBLIC_ALLOW_CREDENTIALS=${NEXT_PUBLIC_ALLOW_CREDENTIALS} - STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
- NEXT_PUBLIC_DISABLE_SIGN_UP=${NEXT_PUBLIC_DISABLE_SIGN_UP} - STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
- NEXT_PUBLIC_POSTHOG_KEY=${NEXT_PUBLIC_POSTHOG_KEY}
- NEXT_PUBLIC_POSTHOG_HOST=${NEXT_PUBLIC_POSTHOG_HOST}
depends_on:
- postgres
restart: unless-stopped
postgres:
image: postgres:15
container_name: kan-db
environment:
- POSTGRES_DB=kan_db
- POSTGRES_USER=kan
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
ports:
- 5432:5432
volumes:
- kan_postgres_data:/var/lib/postgresql/data
restart: unless-stopped
networks:
- kan-network
networks: networks:
kan-network:
dokploy-network: dokploy-network:
external: true external: true
volumes:
kan_postgres_data:

View File

@@ -0,0 +1,17 @@
CREATE TABLE IF NOT EXISTS "integration" (
"provider" varchar(255) NOT NULL,
"userId" uuid NOT NULL,
"accessToken" varchar(255) NOT NULL,
"refreshToken" varchar(255),
"expiresAt" timestamp NOT NULL,
"createdAt" timestamp NOT NULL,
"updatedAt" timestamp,
CONSTRAINT "integration_pkey" PRIMARY KEY("userId","provider")
);
--> statement-breakpoint
ALTER TABLE "integration" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "integration" ADD CONSTRAINT "integration_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View File

@@ -1,6 +1,6 @@
{ {
"id": "d170c8e0-bf75-4c71-abd9-0ecbeeb14003", "id": "d170c8e0-bf75-4c71-abd9-0ecbeeb14003",
"prevId": "1a07a776-0481-49f9-9098-02d530b37cf5", "prevId": "058e8521-2814-46f0-a33f-1bbd86f450ce",
"version": "7", "version": "7",
"dialect": "postgresql", "dialect": "postgresql",
"tables": { "tables": {
@@ -93,12 +93,8 @@
"name": "account_userId_user_id_fk", "name": "account_userId_user_id_fk",
"tableFrom": "account", "tableFrom": "account",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["userId"],
"userId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -246,12 +242,8 @@
"name": "apiKey_userId_user_id_fk", "name": "apiKey_userId_user_id_fk",
"tableFrom": "apiKey", "tableFrom": "apiKey",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["userId"],
"userId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -321,12 +313,8 @@
"name": "session_userId_user_id_fk", "name": "session_userId_user_id_fk",
"tableFrom": "session", "tableFrom": "session",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["userId"],
"userId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -336,9 +324,7 @@
"session_token_unique": { "session_token_unique": {
"name": "session_token_unique", "name": "session_token_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["token"]
"token"
]
} }
}, },
"policies": {}, "policies": {},
@@ -524,12 +510,8 @@
"name": "board_createdBy_user_id_fk", "name": "board_createdBy_user_id_fk",
"tableFrom": "board", "tableFrom": "board",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -537,12 +519,8 @@
"name": "board_deletedBy_user_id_fk", "name": "board_deletedBy_user_id_fk",
"tableFrom": "board", "tableFrom": "board",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["deletedBy"],
"deletedBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -550,12 +528,8 @@
"name": "board_importId_import_id_fk", "name": "board_importId_import_id_fk",
"tableFrom": "board", "tableFrom": "board",
"tableTo": "import", "tableTo": "import",
"columnsFrom": [ "columnsFrom": ["importId"],
"importId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -563,12 +537,8 @@
"name": "board_workspaceId_workspace_id_fk", "name": "board_workspaceId_workspace_id_fk",
"tableFrom": "board", "tableFrom": "board",
"tableTo": "workspace", "tableTo": "workspace",
"columnsFrom": [ "columnsFrom": ["workspaceId"],
"workspaceId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -578,9 +548,7 @@
"board_publicId_unique": { "board_publicId_unique": {
"name": "board_publicId_unique", "name": "board_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
} }
}, },
"policies": {}, "policies": {},
@@ -714,12 +682,8 @@
"name": "card_activity_cardId_card_id_fk", "name": "card_activity_cardId_card_id_fk",
"tableFrom": "card_activity", "tableFrom": "card_activity",
"tableTo": "card", "tableTo": "card",
"columnsFrom": [ "columnsFrom": ["cardId"],
"cardId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -727,12 +691,8 @@
"name": "card_activity_fromListId_list_id_fk", "name": "card_activity_fromListId_list_id_fk",
"tableFrom": "card_activity", "tableFrom": "card_activity",
"tableTo": "list", "tableTo": "list",
"columnsFrom": [ "columnsFrom": ["fromListId"],
"fromListId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -740,12 +700,8 @@
"name": "card_activity_toListId_list_id_fk", "name": "card_activity_toListId_list_id_fk",
"tableFrom": "card_activity", "tableFrom": "card_activity",
"tableTo": "list", "tableTo": "list",
"columnsFrom": [ "columnsFrom": ["toListId"],
"toListId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -753,12 +709,8 @@
"name": "card_activity_labelId_label_id_fk", "name": "card_activity_labelId_label_id_fk",
"tableFrom": "card_activity", "tableFrom": "card_activity",
"tableTo": "label", "tableTo": "label",
"columnsFrom": [ "columnsFrom": ["labelId"],
"labelId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -766,12 +718,8 @@
"name": "card_activity_workspaceMemberId_workspace_members_id_fk", "name": "card_activity_workspaceMemberId_workspace_members_id_fk",
"tableFrom": "card_activity", "tableFrom": "card_activity",
"tableTo": "workspace_members", "tableTo": "workspace_members",
"columnsFrom": [ "columnsFrom": ["workspaceMemberId"],
"workspaceMemberId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -779,12 +727,8 @@
"name": "card_activity_createdBy_user_id_fk", "name": "card_activity_createdBy_user_id_fk",
"tableFrom": "card_activity", "tableFrom": "card_activity",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -792,12 +736,8 @@
"name": "card_activity_commentId_card_comments_id_fk", "name": "card_activity_commentId_card_comments_id_fk",
"tableFrom": "card_activity", "tableFrom": "card_activity",
"tableTo": "card_comments", "tableTo": "card_comments",
"columnsFrom": [ "columnsFrom": ["commentId"],
"commentId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -807,9 +747,7 @@
"card_activity_publicId_unique": { "card_activity_publicId_unique": {
"name": "card_activity_publicId_unique", "name": "card_activity_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
} }
}, },
"policies": {}, "policies": {},
@@ -839,12 +777,8 @@
"name": "_card_workspace_members_cardId_card_id_fk", "name": "_card_workspace_members_cardId_card_id_fk",
"tableFrom": "_card_workspace_members", "tableFrom": "_card_workspace_members",
"tableTo": "card", "tableTo": "card",
"columnsFrom": [ "columnsFrom": ["cardId"],
"cardId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -852,12 +786,8 @@
"name": "_card_workspace_members_workspaceMemberId_workspace_members_id_fk", "name": "_card_workspace_members_workspaceMemberId_workspace_members_id_fk",
"tableFrom": "_card_workspace_members", "tableFrom": "_card_workspace_members",
"tableTo": "workspace_members", "tableTo": "workspace_members",
"columnsFrom": [ "columnsFrom": ["workspaceMemberId"],
"workspaceMemberId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -865,10 +795,7 @@
"compositePrimaryKeys": { "compositePrimaryKeys": {
"_card_workspace_members_cardId_workspaceMemberId_pk": { "_card_workspace_members_cardId_workspaceMemberId_pk": {
"name": "_card_workspace_members_cardId_workspaceMemberId_pk", "name": "_card_workspace_members_cardId_workspaceMemberId_pk",
"columns": [ "columns": ["cardId", "workspaceMemberId"]
"cardId",
"workspaceMemberId"
]
} }
}, },
"uniqueConstraints": {}, "uniqueConstraints": {},
@@ -960,12 +887,8 @@
"name": "card_createdBy_user_id_fk", "name": "card_createdBy_user_id_fk",
"tableFrom": "card", "tableFrom": "card",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -973,12 +896,8 @@
"name": "card_deletedBy_user_id_fk", "name": "card_deletedBy_user_id_fk",
"tableFrom": "card", "tableFrom": "card",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["deletedBy"],
"deletedBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -986,12 +905,8 @@
"name": "card_listId_list_id_fk", "name": "card_listId_list_id_fk",
"tableFrom": "card", "tableFrom": "card",
"tableTo": "list", "tableTo": "list",
"columnsFrom": [ "columnsFrom": ["listId"],
"listId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -999,12 +914,8 @@
"name": "card_importId_import_id_fk", "name": "card_importId_import_id_fk",
"tableFrom": "card", "tableFrom": "card",
"tableTo": "import", "tableTo": "import",
"columnsFrom": [ "columnsFrom": ["importId"],
"importId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1014,9 +925,7 @@
"card_publicId_unique": { "card_publicId_unique": {
"name": "card_publicId_unique", "name": "card_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
} }
}, },
"policies": {}, "policies": {},
@@ -1046,12 +955,8 @@
"name": "_card_labels_cardId_card_id_fk", "name": "_card_labels_cardId_card_id_fk",
"tableFrom": "_card_labels", "tableFrom": "_card_labels",
"tableTo": "card", "tableTo": "card",
"columnsFrom": [ "columnsFrom": ["cardId"],
"cardId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1059,12 +964,8 @@
"name": "_card_labels_labelId_label_id_fk", "name": "_card_labels_labelId_label_id_fk",
"tableFrom": "_card_labels", "tableFrom": "_card_labels",
"tableTo": "label", "tableTo": "label",
"columnsFrom": [ "columnsFrom": ["labelId"],
"labelId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1072,10 +973,7 @@
"compositePrimaryKeys": { "compositePrimaryKeys": {
"_card_labels_cardId_labelId_pk": { "_card_labels_cardId_labelId_pk": {
"name": "_card_labels_cardId_labelId_pk", "name": "_card_labels_cardId_labelId_pk",
"columns": [ "columns": ["cardId", "labelId"]
"cardId",
"labelId"
]
} }
}, },
"uniqueConstraints": {}, "uniqueConstraints": {},
@@ -1149,12 +1047,8 @@
"name": "card_comments_cardId_card_id_fk", "name": "card_comments_cardId_card_id_fk",
"tableFrom": "card_comments", "tableFrom": "card_comments",
"tableTo": "card", "tableTo": "card",
"columnsFrom": [ "columnsFrom": ["cardId"],
"cardId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1162,12 +1056,8 @@
"name": "card_comments_createdBy_user_id_fk", "name": "card_comments_createdBy_user_id_fk",
"tableFrom": "card_comments", "tableFrom": "card_comments",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1175,12 +1065,8 @@
"name": "card_comments_deletedBy_user_id_fk", "name": "card_comments_deletedBy_user_id_fk",
"tableFrom": "card_comments", "tableFrom": "card_comments",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["deletedBy"],
"deletedBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1190,9 +1076,7 @@
"card_comments_publicId_unique": { "card_comments_publicId_unique": {
"name": "card_comments_publicId_unique", "name": "card_comments_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
} }
}, },
"policies": {}, "policies": {},
@@ -1254,12 +1138,8 @@
"name": "feedback_createdBy_user_id_fk", "name": "feedback_createdBy_user_id_fk",
"tableFrom": "feedback", "tableFrom": "feedback",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1320,12 +1200,8 @@
"name": "import_createdBy_user_id_fk", "name": "import_createdBy_user_id_fk",
"tableFrom": "import", "tableFrom": "import",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1335,9 +1211,7 @@
"import_publicId_unique": { "import_publicId_unique": {
"name": "import_publicId_unique", "name": "import_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
} }
}, },
"policies": {}, "policies": {},
@@ -1422,12 +1296,8 @@
"name": "label_createdBy_user_id_fk", "name": "label_createdBy_user_id_fk",
"tableFrom": "label", "tableFrom": "label",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1435,12 +1305,8 @@
"name": "label_boardId_board_id_fk", "name": "label_boardId_board_id_fk",
"tableFrom": "label", "tableFrom": "label",
"tableTo": "board", "tableTo": "board",
"columnsFrom": [ "columnsFrom": ["boardId"],
"boardId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1448,12 +1314,8 @@
"name": "label_importId_import_id_fk", "name": "label_importId_import_id_fk",
"tableFrom": "label", "tableFrom": "label",
"tableTo": "import", "tableTo": "import",
"columnsFrom": [ "columnsFrom": ["importId"],
"importId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1461,12 +1323,8 @@
"name": "label_deletedBy_user_id_fk", "name": "label_deletedBy_user_id_fk",
"tableFrom": "label", "tableFrom": "label",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["deletedBy"],
"deletedBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1476,9 +1334,7 @@
"label_publicId_unique": { "label_publicId_unique": {
"name": "label_publicId_unique", "name": "label_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
} }
}, },
"policies": {}, "policies": {},
@@ -1563,12 +1419,8 @@
"name": "list_createdBy_user_id_fk", "name": "list_createdBy_user_id_fk",
"tableFrom": "list", "tableFrom": "list",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1576,12 +1428,8 @@
"name": "list_deletedBy_user_id_fk", "name": "list_deletedBy_user_id_fk",
"tableFrom": "list", "tableFrom": "list",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["deletedBy"],
"deletedBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1589,12 +1437,8 @@
"name": "list_boardId_board_id_fk", "name": "list_boardId_board_id_fk",
"tableFrom": "list", "tableFrom": "list",
"tableTo": "board", "tableTo": "board",
"columnsFrom": [ "columnsFrom": ["boardId"],
"boardId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1602,12 +1446,8 @@
"name": "list_importId_import_id_fk", "name": "list_importId_import_id_fk",
"tableFrom": "list", "tableFrom": "list",
"tableTo": "import", "tableTo": "import",
"columnsFrom": [ "columnsFrom": ["importId"],
"importId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1617,9 +1457,7 @@
"list_publicId_unique": { "list_publicId_unique": {
"name": "list_publicId_unique", "name": "list_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
} }
}, },
"policies": {}, "policies": {},
@@ -1689,9 +1527,7 @@
"user_email_unique": { "user_email_unique": {
"name": "user_email_unique", "name": "user_email_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["email"]
"email"
]
} }
}, },
"policies": {}, "policies": {},
@@ -1751,12 +1587,8 @@
"name": "integration_userId_user_id_fk", "name": "integration_userId_user_id_fk",
"tableFrom": "integration", "tableFrom": "integration",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["userId"],
"userId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1764,10 +1596,7 @@
"compositePrimaryKeys": { "compositePrimaryKeys": {
"integration_pkey": { "integration_pkey": {
"name": "integration_pkey", "name": "integration_pkey",
"columns": [ "columns": ["userId", "provider"]
"userId",
"provider"
]
} }
}, },
"uniqueConstraints": {}, "uniqueConstraints": {},
@@ -1800,9 +1629,7 @@
"workspace_slugs_slug_unique": { "workspace_slugs_slug_unique": {
"name": "workspace_slugs_slug_unique", "name": "workspace_slugs_slug_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["slug"]
"slug"
]
} }
}, },
"policies": {}, "policies": {},
@@ -1896,12 +1723,8 @@
"name": "workspace_members_userId_user_id_fk", "name": "workspace_members_userId_user_id_fk",
"tableFrom": "workspace_members", "tableFrom": "workspace_members",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["userId"],
"userId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1909,12 +1732,8 @@
"name": "workspace_members_workspaceId_workspace_id_fk", "name": "workspace_members_workspaceId_workspace_id_fk",
"tableFrom": "workspace_members", "tableFrom": "workspace_members",
"tableTo": "workspace", "tableTo": "workspace",
"columnsFrom": [ "columnsFrom": ["workspaceId"],
"workspaceId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1922,12 +1741,8 @@
"name": "workspace_members_deletedBy_user_id_fk", "name": "workspace_members_deletedBy_user_id_fk",
"tableFrom": "workspace_members", "tableFrom": "workspace_members",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["deletedBy"],
"deletedBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1937,9 +1752,7 @@
"workspace_members_publicId_unique": { "workspace_members_publicId_unique": {
"name": "workspace_members_publicId_unique", "name": "workspace_members_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
} }
}, },
"policies": {}, "policies": {},
@@ -2026,12 +1839,8 @@
"name": "workspace_createdBy_user_id_fk", "name": "workspace_createdBy_user_id_fk",
"tableFrom": "workspace", "tableFrom": "workspace",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -2039,12 +1848,8 @@
"name": "workspace_deletedBy_user_id_fk", "name": "workspace_deletedBy_user_id_fk",
"tableFrom": "workspace", "tableFrom": "workspace",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["deletedBy"],
"deletedBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -2054,16 +1859,12 @@
"workspace_publicId_unique": { "workspace_publicId_unique": {
"name": "workspace_publicId_unique", "name": "workspace_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
}, },
"workspace_slug_unique": { "workspace_slug_unique": {
"name": "workspace_slug_unique", "name": "workspace_slug_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["slug"]
"slug"
]
} }
}, },
"policies": {}, "policies": {},
@@ -2075,10 +1876,7 @@
"public.board_visibility": { "public.board_visibility": {
"name": "board_visibility", "name": "board_visibility",
"schema": "public", "schema": "public",
"values": [ "values": ["private", "public"]
"private",
"public"
]
}, },
"public.card_activity_type": { "public.card_activity_type": {
"name": "card_activity_type", "name": "card_activity_type",
@@ -2102,53 +1900,32 @@
"public.source": { "public.source": {
"name": "source", "name": "source",
"schema": "public", "schema": "public",
"values": [ "values": ["trello"]
"trello"
]
}, },
"public.status": { "public.status": {
"name": "status", "name": "status",
"schema": "public", "schema": "public",
"values": [ "values": ["started", "success", "failed"]
"started",
"success",
"failed"
]
}, },
"public.role": { "public.role": {
"name": "role", "name": "role",
"schema": "public", "schema": "public",
"values": [ "values": ["admin", "member", "guest"]
"admin",
"member",
"guest"
]
}, },
"public.member_status": { "public.member_status": {
"name": "member_status", "name": "member_status",
"schema": "public", "schema": "public",
"values": [ "values": ["invited", "active", "removed"]
"invited",
"active",
"removed"
]
}, },
"public.slug_type": { "public.slug_type": {
"name": "slug_type", "name": "slug_type",
"schema": "public", "schema": "public",
"values": [ "values": ["reserved", "premium"]
"reserved",
"premium"
]
}, },
"public.workspace_plan": { "public.workspace_plan": {
"name": "workspace_plan", "name": "workspace_plan",
"schema": "public", "schema": "public",
"values": [ "values": ["free", "pro", "enterprise"]
"free",
"pro",
"enterprise"
]
} }
}, },
"schemas": {}, "schemas": {},
@@ -2161,4 +1938,4 @@
"schemas": {}, "schemas": {},
"tables": {} "tables": {}
} }
} }

View File

@@ -93,12 +93,8 @@
"name": "account_userId_user_id_fk", "name": "account_userId_user_id_fk",
"tableFrom": "account", "tableFrom": "account",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["userId"],
"userId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -246,12 +242,8 @@
"name": "apiKey_userId_user_id_fk", "name": "apiKey_userId_user_id_fk",
"tableFrom": "apiKey", "tableFrom": "apiKey",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["userId"],
"userId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -321,12 +313,8 @@
"name": "session_userId_user_id_fk", "name": "session_userId_user_id_fk",
"tableFrom": "session", "tableFrom": "session",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["userId"],
"userId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -336,9 +324,7 @@
"session_token_unique": { "session_token_unique": {
"name": "session_token_unique", "name": "session_token_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["token"]
"token"
]
} }
}, },
"policies": {}, "policies": {},
@@ -524,12 +510,8 @@
"name": "board_createdBy_user_id_fk", "name": "board_createdBy_user_id_fk",
"tableFrom": "board", "tableFrom": "board",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -537,12 +519,8 @@
"name": "board_deletedBy_user_id_fk", "name": "board_deletedBy_user_id_fk",
"tableFrom": "board", "tableFrom": "board",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["deletedBy"],
"deletedBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -550,12 +528,8 @@
"name": "board_importId_import_id_fk", "name": "board_importId_import_id_fk",
"tableFrom": "board", "tableFrom": "board",
"tableTo": "import", "tableTo": "import",
"columnsFrom": [ "columnsFrom": ["importId"],
"importId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -563,12 +537,8 @@
"name": "board_workspaceId_workspace_id_fk", "name": "board_workspaceId_workspace_id_fk",
"tableFrom": "board", "tableFrom": "board",
"tableTo": "workspace", "tableTo": "workspace",
"columnsFrom": [ "columnsFrom": ["workspaceId"],
"workspaceId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -578,9 +548,7 @@
"board_publicId_unique": { "board_publicId_unique": {
"name": "board_publicId_unique", "name": "board_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
} }
}, },
"policies": {}, "policies": {},
@@ -714,12 +682,8 @@
"name": "card_activity_cardId_card_id_fk", "name": "card_activity_cardId_card_id_fk",
"tableFrom": "card_activity", "tableFrom": "card_activity",
"tableTo": "card", "tableTo": "card",
"columnsFrom": [ "columnsFrom": ["cardId"],
"cardId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -727,12 +691,8 @@
"name": "card_activity_fromListId_list_id_fk", "name": "card_activity_fromListId_list_id_fk",
"tableFrom": "card_activity", "tableFrom": "card_activity",
"tableTo": "list", "tableTo": "list",
"columnsFrom": [ "columnsFrom": ["fromListId"],
"fromListId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -740,12 +700,8 @@
"name": "card_activity_toListId_list_id_fk", "name": "card_activity_toListId_list_id_fk",
"tableFrom": "card_activity", "tableFrom": "card_activity",
"tableTo": "list", "tableTo": "list",
"columnsFrom": [ "columnsFrom": ["toListId"],
"toListId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -753,12 +709,8 @@
"name": "card_activity_labelId_label_id_fk", "name": "card_activity_labelId_label_id_fk",
"tableFrom": "card_activity", "tableFrom": "card_activity",
"tableTo": "label", "tableTo": "label",
"columnsFrom": [ "columnsFrom": ["labelId"],
"labelId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -766,12 +718,8 @@
"name": "card_activity_workspaceMemberId_workspace_members_id_fk", "name": "card_activity_workspaceMemberId_workspace_members_id_fk",
"tableFrom": "card_activity", "tableFrom": "card_activity",
"tableTo": "workspace_members", "tableTo": "workspace_members",
"columnsFrom": [ "columnsFrom": ["workspaceMemberId"],
"workspaceMemberId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -779,12 +727,8 @@
"name": "card_activity_createdBy_user_id_fk", "name": "card_activity_createdBy_user_id_fk",
"tableFrom": "card_activity", "tableFrom": "card_activity",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -792,12 +736,8 @@
"name": "card_activity_commentId_card_comments_id_fk", "name": "card_activity_commentId_card_comments_id_fk",
"tableFrom": "card_activity", "tableFrom": "card_activity",
"tableTo": "card_comments", "tableTo": "card_comments",
"columnsFrom": [ "columnsFrom": ["commentId"],
"commentId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -807,9 +747,7 @@
"card_activity_publicId_unique": { "card_activity_publicId_unique": {
"name": "card_activity_publicId_unique", "name": "card_activity_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
} }
}, },
"policies": {}, "policies": {},
@@ -839,12 +777,8 @@
"name": "_card_workspace_members_cardId_card_id_fk", "name": "_card_workspace_members_cardId_card_id_fk",
"tableFrom": "_card_workspace_members", "tableFrom": "_card_workspace_members",
"tableTo": "card", "tableTo": "card",
"columnsFrom": [ "columnsFrom": ["cardId"],
"cardId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -852,12 +786,8 @@
"name": "_card_workspace_members_workspaceMemberId_workspace_members_id_fk", "name": "_card_workspace_members_workspaceMemberId_workspace_members_id_fk",
"tableFrom": "_card_workspace_members", "tableFrom": "_card_workspace_members",
"tableTo": "workspace_members", "tableTo": "workspace_members",
"columnsFrom": [ "columnsFrom": ["workspaceMemberId"],
"workspaceMemberId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -865,10 +795,7 @@
"compositePrimaryKeys": { "compositePrimaryKeys": {
"_card_workspace_members_cardId_workspaceMemberId_pk": { "_card_workspace_members_cardId_workspaceMemberId_pk": {
"name": "_card_workspace_members_cardId_workspaceMemberId_pk", "name": "_card_workspace_members_cardId_workspaceMemberId_pk",
"columns": [ "columns": ["cardId", "workspaceMemberId"]
"cardId",
"workspaceMemberId"
]
} }
}, },
"uniqueConstraints": {}, "uniqueConstraints": {},
@@ -960,12 +887,8 @@
"name": "card_createdBy_user_id_fk", "name": "card_createdBy_user_id_fk",
"tableFrom": "card", "tableFrom": "card",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -973,12 +896,8 @@
"name": "card_deletedBy_user_id_fk", "name": "card_deletedBy_user_id_fk",
"tableFrom": "card", "tableFrom": "card",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["deletedBy"],
"deletedBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -986,12 +905,8 @@
"name": "card_listId_list_id_fk", "name": "card_listId_list_id_fk",
"tableFrom": "card", "tableFrom": "card",
"tableTo": "list", "tableTo": "list",
"columnsFrom": [ "columnsFrom": ["listId"],
"listId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -999,12 +914,8 @@
"name": "card_importId_import_id_fk", "name": "card_importId_import_id_fk",
"tableFrom": "card", "tableFrom": "card",
"tableTo": "import", "tableTo": "import",
"columnsFrom": [ "columnsFrom": ["importId"],
"importId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1014,9 +925,7 @@
"card_publicId_unique": { "card_publicId_unique": {
"name": "card_publicId_unique", "name": "card_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
} }
}, },
"policies": {}, "policies": {},
@@ -1046,12 +955,8 @@
"name": "_card_labels_cardId_card_id_fk", "name": "_card_labels_cardId_card_id_fk",
"tableFrom": "_card_labels", "tableFrom": "_card_labels",
"tableTo": "card", "tableTo": "card",
"columnsFrom": [ "columnsFrom": ["cardId"],
"cardId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1059,12 +964,8 @@
"name": "_card_labels_labelId_label_id_fk", "name": "_card_labels_labelId_label_id_fk",
"tableFrom": "_card_labels", "tableFrom": "_card_labels",
"tableTo": "label", "tableTo": "label",
"columnsFrom": [ "columnsFrom": ["labelId"],
"labelId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1072,10 +973,7 @@
"compositePrimaryKeys": { "compositePrimaryKeys": {
"_card_labels_cardId_labelId_pk": { "_card_labels_cardId_labelId_pk": {
"name": "_card_labels_cardId_labelId_pk", "name": "_card_labels_cardId_labelId_pk",
"columns": [ "columns": ["cardId", "labelId"]
"cardId",
"labelId"
]
} }
}, },
"uniqueConstraints": {}, "uniqueConstraints": {},
@@ -1149,12 +1047,8 @@
"name": "card_comments_cardId_card_id_fk", "name": "card_comments_cardId_card_id_fk",
"tableFrom": "card_comments", "tableFrom": "card_comments",
"tableTo": "card", "tableTo": "card",
"columnsFrom": [ "columnsFrom": ["cardId"],
"cardId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1162,12 +1056,8 @@
"name": "card_comments_createdBy_user_id_fk", "name": "card_comments_createdBy_user_id_fk",
"tableFrom": "card_comments", "tableFrom": "card_comments",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1175,12 +1065,8 @@
"name": "card_comments_deletedBy_user_id_fk", "name": "card_comments_deletedBy_user_id_fk",
"tableFrom": "card_comments", "tableFrom": "card_comments",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["deletedBy"],
"deletedBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1190,9 +1076,7 @@
"card_comments_publicId_unique": { "card_comments_publicId_unique": {
"name": "card_comments_publicId_unique", "name": "card_comments_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
} }
}, },
"policies": {}, "policies": {},
@@ -1254,12 +1138,8 @@
"name": "feedback_createdBy_user_id_fk", "name": "feedback_createdBy_user_id_fk",
"tableFrom": "feedback", "tableFrom": "feedback",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1320,12 +1200,8 @@
"name": "import_createdBy_user_id_fk", "name": "import_createdBy_user_id_fk",
"tableFrom": "import", "tableFrom": "import",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1335,9 +1211,7 @@
"import_publicId_unique": { "import_publicId_unique": {
"name": "import_publicId_unique", "name": "import_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
} }
}, },
"policies": {}, "policies": {},
@@ -1422,12 +1296,8 @@
"name": "label_createdBy_user_id_fk", "name": "label_createdBy_user_id_fk",
"tableFrom": "label", "tableFrom": "label",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1435,12 +1305,8 @@
"name": "label_boardId_board_id_fk", "name": "label_boardId_board_id_fk",
"tableFrom": "label", "tableFrom": "label",
"tableTo": "board", "tableTo": "board",
"columnsFrom": [ "columnsFrom": ["boardId"],
"boardId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1448,12 +1314,8 @@
"name": "label_importId_import_id_fk", "name": "label_importId_import_id_fk",
"tableFrom": "label", "tableFrom": "label",
"tableTo": "import", "tableTo": "import",
"columnsFrom": [ "columnsFrom": ["importId"],
"importId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1461,12 +1323,8 @@
"name": "label_deletedBy_user_id_fk", "name": "label_deletedBy_user_id_fk",
"tableFrom": "label", "tableFrom": "label",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["deletedBy"],
"deletedBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1476,9 +1334,7 @@
"label_publicId_unique": { "label_publicId_unique": {
"name": "label_publicId_unique", "name": "label_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
} }
}, },
"policies": {}, "policies": {},
@@ -1563,12 +1419,8 @@
"name": "list_createdBy_user_id_fk", "name": "list_createdBy_user_id_fk",
"tableFrom": "list", "tableFrom": "list",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1576,12 +1428,8 @@
"name": "list_deletedBy_user_id_fk", "name": "list_deletedBy_user_id_fk",
"tableFrom": "list", "tableFrom": "list",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["deletedBy"],
"deletedBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1589,12 +1437,8 @@
"name": "list_boardId_board_id_fk", "name": "list_boardId_board_id_fk",
"tableFrom": "list", "tableFrom": "list",
"tableTo": "board", "tableTo": "board",
"columnsFrom": [ "columnsFrom": ["boardId"],
"boardId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1602,12 +1446,8 @@
"name": "list_importId_import_id_fk", "name": "list_importId_import_id_fk",
"tableFrom": "list", "tableFrom": "list",
"tableTo": "import", "tableTo": "import",
"columnsFrom": [ "columnsFrom": ["importId"],
"importId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "no action", "onDelete": "no action",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1617,9 +1457,7 @@
"list_publicId_unique": { "list_publicId_unique": {
"name": "list_publicId_unique", "name": "list_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
} }
}, },
"policies": {}, "policies": {},
@@ -1689,9 +1527,7 @@
"user_email_unique": { "user_email_unique": {
"name": "user_email_unique", "name": "user_email_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["email"]
"email"
]
} }
}, },
"policies": {}, "policies": {},
@@ -1723,9 +1559,7 @@
"workspace_slugs_slug_unique": { "workspace_slugs_slug_unique": {
"name": "workspace_slugs_slug_unique", "name": "workspace_slugs_slug_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["slug"]
"slug"
]
} }
}, },
"policies": {}, "policies": {},
@@ -1819,12 +1653,8 @@
"name": "workspace_members_userId_user_id_fk", "name": "workspace_members_userId_user_id_fk",
"tableFrom": "workspace_members", "tableFrom": "workspace_members",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["userId"],
"userId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1832,12 +1662,8 @@
"name": "workspace_members_workspaceId_workspace_id_fk", "name": "workspace_members_workspaceId_workspace_id_fk",
"tableFrom": "workspace_members", "tableFrom": "workspace_members",
"tableTo": "workspace", "tableTo": "workspace",
"columnsFrom": [ "columnsFrom": ["workspaceId"],
"workspaceId" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1845,12 +1671,8 @@
"name": "workspace_members_deletedBy_user_id_fk", "name": "workspace_members_deletedBy_user_id_fk",
"tableFrom": "workspace_members", "tableFrom": "workspace_members",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["deletedBy"],
"deletedBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1860,9 +1682,7 @@
"workspace_members_publicId_unique": { "workspace_members_publicId_unique": {
"name": "workspace_members_publicId_unique", "name": "workspace_members_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
} }
}, },
"policies": {}, "policies": {},
@@ -1949,12 +1769,8 @@
"name": "workspace_createdBy_user_id_fk", "name": "workspace_createdBy_user_id_fk",
"tableFrom": "workspace", "tableFrom": "workspace",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["createdBy"],
"createdBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@@ -1962,12 +1778,8 @@
"name": "workspace_deletedBy_user_id_fk", "name": "workspace_deletedBy_user_id_fk",
"tableFrom": "workspace", "tableFrom": "workspace",
"tableTo": "user", "tableTo": "user",
"columnsFrom": [ "columnsFrom": ["deletedBy"],
"deletedBy" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "set null", "onDelete": "set null",
"onUpdate": "no action" "onUpdate": "no action"
} }
@@ -1977,16 +1789,12 @@
"workspace_publicId_unique": { "workspace_publicId_unique": {
"name": "workspace_publicId_unique", "name": "workspace_publicId_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["publicId"]
"publicId"
]
}, },
"workspace_slug_unique": { "workspace_slug_unique": {
"name": "workspace_slug_unique", "name": "workspace_slug_unique",
"nullsNotDistinct": false, "nullsNotDistinct": false,
"columns": [ "columns": ["slug"]
"slug"
]
} }
}, },
"policies": {}, "policies": {},
@@ -1998,10 +1806,7 @@
"public.board_visibility": { "public.board_visibility": {
"name": "board_visibility", "name": "board_visibility",
"schema": "public", "schema": "public",
"values": [ "values": ["private", "public"]
"private",
"public"
]
}, },
"public.card_activity_type": { "public.card_activity_type": {
"name": "card_activity_type", "name": "card_activity_type",
@@ -2025,53 +1830,32 @@
"public.source": { "public.source": {
"name": "source", "name": "source",
"schema": "public", "schema": "public",
"values": [ "values": ["trello"]
"trello"
]
}, },
"public.status": { "public.status": {
"name": "status", "name": "status",
"schema": "public", "schema": "public",
"values": [ "values": ["started", "success", "failed"]
"started",
"success",
"failed"
]
}, },
"public.role": { "public.role": {
"name": "role", "name": "role",
"schema": "public", "schema": "public",
"values": [ "values": ["admin", "member", "guest"]
"admin",
"member",
"guest"
]
}, },
"public.member_status": { "public.member_status": {
"name": "member_status", "name": "member_status",
"schema": "public", "schema": "public",
"values": [ "values": ["invited", "active", "removed"]
"invited",
"active",
"removed"
]
}, },
"public.slug_type": { "public.slug_type": {
"name": "slug_type", "name": "slug_type",
"schema": "public", "schema": "public",
"values": [ "values": ["reserved", "premium"]
"reserved",
"premium"
]
}, },
"public.workspace_plan": { "public.workspace_plan": {
"name": "workspace_plan", "name": "workspace_plan",
"schema": "public", "schema": "public",
"values": [ "values": ["free", "pro", "enterprise"]
"free",
"pro",
"enterprise"
]
} }
}, },
"schemas": {}, "schemas": {},
@@ -2084,4 +1868,4 @@
"schemas": {}, "schemas": {},
"tables": {} "tables": {}
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -43,6 +43,13 @@
"when": 1749377372062, "when": 1749377372062,
"tag": "20250608100932_AddIntegrationsTable", "tag": "20250608100932_AddIntegrationsTable",
"breakpoints": true "breakpoints": true
},
{
"idx": 6,
"version": "7",
"when": 1749585889984,
"tag": "20250610200449_ReaddIntegrationTable",
"breakpoints": true
} }
] ]
} }

View File

@@ -29,22 +29,34 @@ export const sendEmail = async (
template: Templates, template: Templates,
data: Record<string, string>, data: Record<string, string>,
) => { ) => {
const EmailTemplate = emailTemplates[template]; try {
const EmailTemplate = emailTemplates[template];
const html = await render(<EmailTemplate {...data} />, { pretty: true }); const html = await render(<EmailTemplate {...data} />, { pretty: true });
const options = { const options = {
from: process.env.EMAIL_FROM, from: process.env.EMAIL_FROM,
to, to,
subject, subject,
html, html,
}; };
const response = await transporter.sendMail(options); const response = await transporter.sendMail(options);
if (!response.accepted.length) { if (!response.accepted.length) {
throw new Error(`Failed to send email: ${response.response}`); throw new Error(`Failed to send email: ${response.response}`);
}
return response;
} catch (error) {
console.error("Email sending failed:", {
to,
from: process.env.EMAIL_FROM,
subject,
template,
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
});
throw error;
} }
return response;
}; };

41
pnpm-lock.yaml generated
View File

@@ -159,6 +159,9 @@ importers:
pino: pino:
specifier: ^9.6.0 specifier: ^9.6.0
version: 9.6.0 version: 9.6.0
posthog-js:
specifier: ^1.254.0
version: 1.254.0
react: react:
specifier: catalog:react18 specifier: catalog:react18
version: 18.3.1 version: 18.3.1
@@ -3064,6 +3067,9 @@ packages:
core-js-pure@3.39.0: core-js-pure@3.39.0:
resolution: {integrity: sha512-7fEcWwKI4rJinnK+wLTezeg2smbFFdSBP6E2kQZNbnzM2s1rpKQ6aaRteZSSg7FLU3P0HGGVo/gbpfanU36urg==} resolution: {integrity: sha512-7fEcWwKI4rJinnK+wLTezeg2smbFFdSBP6E2kQZNbnzM2s1rpKQ6aaRteZSSg7FLU3P0HGGVo/gbpfanU36urg==}
core-js@3.43.0:
resolution: {integrity: sha512-N6wEbTTZSYOY2rYAn85CuvWWkCK6QweMn7/4Nr3w+gDBeBhk/x4EJeY6FPo4QzDoJZxVTv8U7CMvgWk6pOHHqA==}
cors@2.8.5: cors@2.8.5:
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
engines: {node: '>= 0.10'} engines: {node: '>= 0.10'}
@@ -3664,6 +3670,9 @@ packages:
resolution: {integrity: sha512-k/2rVBRIRzOeom3wI9jBPaSEvoTSQEW4iM0EveBmBBKFxO8mSyyRWtDlfC3VnEfu0avmjrMzy8/ZFPSe6F71Hw==} resolution: {integrity: sha512-k/2rVBRIRzOeom3wI9jBPaSEvoTSQEW4iM0EveBmBBKFxO8mSyyRWtDlfC3VnEfu0avmjrMzy8/ZFPSe6F71Hw==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
fflate@0.4.8:
resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==}
figures@3.2.0: figures@3.2.0:
resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -5199,6 +5208,20 @@ packages:
resolution: {integrity: sha512-cDWgoah1Gez9rN3H4165peY9qfpEo+SA61oQv65O3cRUE1pOEoJWwddwcqKE8XZYjbblOJlYDlLV4h67HrEVDg==} resolution: {integrity: sha512-cDWgoah1Gez9rN3H4165peY9qfpEo+SA61oQv65O3cRUE1pOEoJWwddwcqKE8XZYjbblOJlYDlLV4h67HrEVDg==}
engines: {node: '>=12'} engines: {node: '>=12'}
posthog-js@1.254.0:
resolution: {integrity: sha512-ISJEsYTIx8FJ0W78q2lfueSrrcuNKCjGfgk9LLuRhAfxRJ+N5ljyGreeEWVrkli2QJBAWje0qYUcregBcIs33A==}
peerDependencies:
'@rrweb/types': 2.0.0-alpha.17
rrweb-snapshot: 2.0.0-alpha.17
peerDependenciesMeta:
'@rrweb/types':
optional: true
rrweb-snapshot:
optional: true
preact@10.26.9:
resolution: {integrity: sha512-SSjF9vcnF27mJK1XyFMNJzFd5u3pQiATFqoaDy03XuN00u4ziveVVEGt5RKJrDR8MHE/wJo9Nnad56RLzS2RMA==}
prelude-ls@1.2.1: prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
@@ -6250,6 +6273,9 @@ packages:
wcwidth@1.0.1: wcwidth@1.0.1:
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
web-vitals@4.2.4:
resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==}
webidl-conversions@3.0.1: webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
@@ -9375,6 +9401,8 @@ snapshots:
core-js-pure@3.39.0: {} core-js-pure@3.39.0: {}
core-js@3.43.0: {}
cors@2.8.5: cors@2.8.5:
dependencies: dependencies:
object-assign: 4.1.1 object-assign: 4.1.1
@@ -10079,6 +10107,8 @@ snapshots:
sharp: 0.33.5 sharp: 0.33.5
xml2js: 0.6.2 xml2js: 0.6.2
fflate@0.4.8: {}
figures@3.2.0: figures@3.2.0:
dependencies: dependencies:
escape-string-regexp: 1.0.5 escape-string-regexp: 1.0.5
@@ -12078,6 +12108,15 @@ snapshots:
postgres@3.4.5: postgres@3.4.5:
optional: true optional: true
posthog-js@1.254.0:
dependencies:
core-js: 3.43.0
fflate: 0.4.8
preact: 10.26.9
web-vitals: 4.2.4
preact@10.26.9: {}
prelude-ls@1.2.1: {} prelude-ls@1.2.1: {}
prettier-plugin-tailwindcss@0.6.9(@ianvs/prettier-plugin-sort-imports@4.4.0(prettier@3.4.2))(prettier@3.4.2): prettier-plugin-tailwindcss@0.6.9(@ianvs/prettier-plugin-sort-imports@4.4.0(prettier@3.4.2))(prettier@3.4.2):
@@ -13320,6 +13359,8 @@ snapshots:
dependencies: dependencies:
defaults: 1.0.4 defaults: 1.0.4
web-vitals@4.2.4: {}
webidl-conversions@3.0.1: {} webidl-conversions@3.0.1: {}
whatwg-url@5.0.0: whatwg-url@5.0.0:

View File

@@ -100,6 +100,7 @@
"NEXT_PUBLIC_AVATAR_BUCKET_NAME", "NEXT_PUBLIC_AVATAR_BUCKET_NAME",
"NEXT_PUBLIC_ALLOW_CREDENTIALS", "NEXT_PUBLIC_ALLOW_CREDENTIALS",
"NEXT_PUBLIC_DISABLE_SIGN_UP", "NEXT_PUBLIC_DISABLE_SIGN_UP",
"NEXT_PUBLIC_USE_STANDALONE_OUTPUT",
"S3_REGION", "S3_REGION",
"S3_ACCESS_KEY_ID", "S3_ACCESS_KEY_ID",
"S3_SECRET_ACCESS_KEY", "S3_SECRET_ACCESS_KEY",