Compare commits
8 Commits
feat/reduc
...
feat/smtp-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09a190d6fb | ||
|
|
5586c26c12 | ||
|
|
2d7097eb83 | ||
|
|
2aa898da00 | ||
|
|
a01a826bac | ||
|
|
a29ea76024 | ||
|
|
e1c6bfd6cd | ||
|
|
c272c38f6b |
@@ -12,5 +12,12 @@ if [ $? -ne 0 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "\nStarting Next.js application..."
|
echo "\nStarting Next.js application..."
|
||||||
# Start the Next.js application from the web app's directory
|
|
||||||
exec node .next/standalone/apps/web/server.js
|
# 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
|
||||||
@@ -10,7 +10,10 @@ configureRuntimeEnv();
|
|||||||
|
|
||||||
/** @type {import("next").NextConfig} */
|
/** @type {import("next").NextConfig} */
|
||||||
const config = {
|
const config = {
|
||||||
// output: "standalone",
|
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 */
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ export const env = createEnv({
|
|||||||
NEXT_PUBLIC_UMAMI_ID: z.string().optional(),
|
NEXT_PUBLIC_UMAMI_ID: z.string().optional(),
|
||||||
NEXT_PUBLIC_POSTHOG_KEY: z.string().optional(),
|
NEXT_PUBLIC_POSTHOG_KEY: z.string().optional(),
|
||||||
NEXT_PUBLIC_POSTHOG_HOST: 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(),
|
||||||
@@ -115,6 +116,8 @@ export const env = createEnv({
|
|||||||
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",
|
||||||
|
|||||||
63
cloud/docker-compose.yml
Normal file
63
cloud/docker-compose.yml
Normal 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
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
services:
|
|
||||||
web:
|
|
||||||
image: ghcr.io/kanbn/kan:latest
|
|
||||||
ports:
|
|
||||||
- "3001:3000"
|
|
||||||
networks:
|
|
||||||
- dokploy-network
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: ./apps/web/Dockerfile
|
|
||||||
env_file:
|
|
||||||
- .env
|
|
||||||
command: ["pnpm", "start"]
|
|
||||||
environment:
|
|
||||||
- EMAIL_FROM=${EMAIL_FROM}
|
|
||||||
- SMTP_HOST=${SMTP_HOST}
|
|
||||||
- SMTP_PORT=${SMTP_PORT}
|
|
||||||
- SMTP_USER=${SMTP_USER}
|
|
||||||
- SMTP_PASSWORD=${SMTP_PASSWORD}
|
|
||||||
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
|
|
||||||
- BETTER_AUTH_TRUSTED_ORIGINS=${BETTER_AUTH_TRUSTED_ORIGINS}
|
|
||||||
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
|
|
||||||
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
|
|
||||||
- POSTGRES_URL=${POSTGRES_URL}
|
|
||||||
- TRELLO_APP_API_KEY=${TRELLO_APP_API_KEY}
|
|
||||||
- TRELLO_APP_SECRET=${TRELLO_APP_SECRET}
|
|
||||||
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
|
|
||||||
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
|
|
||||||
- DISCORD_CLIENT_ID=${DISCORD_CLIENT_ID}
|
|
||||||
- DISCORD_CLIENT_SECRET=${DISCORD_CLIENT_SECRET}
|
|
||||||
- GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID}
|
|
||||||
- GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET}
|
|
||||||
- GITLAB_CLIENT_ID=${GITLAB_CLIENT_ID}
|
|
||||||
- GITLAB_CLIENT_SECRET=${GITLAB_CLIENT_SECRET}
|
|
||||||
- GITLAB_ISSUER=${GITLAB_ISSUER}
|
|
||||||
- MICROSOFT_CLIENT_ID=${MICROSOFT_CLIENT_ID}
|
|
||||||
- MICROSOFT_CLIENT_SECRET=${MICROSOFT_CLIENT_SECRET}
|
|
||||||
- TWITTER_CLIENT_ID=${TWITTER_CLIENT_ID}
|
|
||||||
- TWITTER_CLIENT_SECRET=${TWITTER_CLIENT_SECRET}
|
|
||||||
- KICK_CLIENT_ID=${KICK_CLIENT_ID}
|
|
||||||
- KICK_CLIENT_SECRET=${KICK_CLIENT_SECRET}
|
|
||||||
- ZOOM_CLIENT_ID=${ZOOM_CLIENT_ID}
|
|
||||||
- ZOOM_CLIENT_SECRET=${ZOOM_CLIENT_SECRET}
|
|
||||||
- DROPBOX_CLIENT_ID=${DROPBOX_CLIENT_ID}
|
|
||||||
- DROPBOX_CLIENT_SECRET=${DROPBOX_CLIENT_SECRET}
|
|
||||||
- VK_CLIENT_ID=${VK_CLIENT_ID}
|
|
||||||
- VK_CLIENT_SECRET=${VK_CLIENT_SECRET}
|
|
||||||
- LINKEDIN_CLIENT_ID=${LINKEDIN_CLIENT_ID}
|
|
||||||
- LINKEDIN_CLIENT_SECRET=${LINKEDIN_CLIENT_SECRET}
|
|
||||||
- REDDIT_CLIENT_ID=${REDDIT_CLIENT_ID}
|
|
||||||
- REDDIT_CLIENT_SECRET=${REDDIT_CLIENT_SECRET}
|
|
||||||
- ROBLOX_CLIENT_ID=${ROBLOX_CLIENT_ID}
|
|
||||||
- ROBLOX_CLIENT_SECRET=${ROBLOX_CLIENT_SECRET}
|
|
||||||
- SPOTIFY_CLIENT_ID=${SPOTIFY_CLIENT_ID}
|
|
||||||
- SPOTIFY_CLIENT_SECRET=${SPOTIFY_CLIENT_SECRET}
|
|
||||||
- TIKTOK_CLIENT_ID=${TIKTOK_CLIENT_ID}
|
|
||||||
- TIKTOK_CLIENT_SECRET=${TIKTOK_CLIENT_SECRET}
|
|
||||||
- TIKTOK_CLIENT_KEY=${TIKTOK_CLIENT_KEY}
|
|
||||||
- TWITCH_CLIENT_ID=${TWITCH_CLIENT_ID}
|
|
||||||
- TWITCH_CLIENT_SECRET=${TWITCH_CLIENT_SECRET}
|
|
||||||
- APPLE_CLIENT_ID=${APPLE_CLIENT_ID}
|
|
||||||
- APPLE_CLIENT_SECRET=${APPLE_CLIENT_SECRET}
|
|
||||||
- APPLE_APP_BUNDLE_IDENTIFIER=${APPLE_APP_BUNDLE_IDENTIFIER}
|
|
||||||
- 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_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_ALLOW_CREDENTIALS=${NEXT_PUBLIC_ALLOW_CREDENTIALS}
|
|
||||||
- NEXT_PUBLIC_DISABLE_SIGN_UP=${NEXT_PUBLIC_DISABLE_SIGN_UP}
|
|
||||||
- NEXT_PUBLIC_POSTHOG_KEY=${NEXT_PUBLIC_POSTHOG_KEY}
|
|
||||||
- NEXT_PUBLIC_POSTHOG_HOST=${NEXT_PUBLIC_POSTHOG_HOST}
|
|
||||||
networks:
|
|
||||||
dokploy-network:
|
|
||||||
external: true
|
|
||||||
#bump
|
|
||||||
@@ -9,7 +9,7 @@ services:
|
|||||||
- dokploy-network
|
- dokploy-network
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./apps/web/Dockerfile
|
dockerfile: ./apps/web/Dockerfile.new
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export const sendEmail = async (
|
|||||||
template: Templates,
|
template: Templates,
|
||||||
data: Record<string, string>,
|
data: Record<string, string>,
|
||||||
) => {
|
) => {
|
||||||
|
try {
|
||||||
const EmailTemplate = emailTemplates[template];
|
const EmailTemplate = emailTemplates[template];
|
||||||
|
|
||||||
const html = await render(<EmailTemplate {...data} />, { pretty: true });
|
const html = await render(<EmailTemplate {...data} />, { pretty: true });
|
||||||
@@ -47,4 +48,15 @@ export const sendEmail = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
return 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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
Reference in New Issue
Block a user