feat: add a docker compose file
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
|
## Supabase - DB
|
||||||
PUBLIC_SUPABASE_ANON_KEY=
|
PUBLIC_SUPABASE_ANON_KEY=
|
||||||
PUBLIC_SUPABASE_URL=
|
PUBLIC_SUPABASE_URL=
|
||||||
|
|
||||||
|
## Cloudflare - Video uploads
|
||||||
# Not required - https://cdn.example.com
|
# Not required - https://cdn.example.com
|
||||||
CLOUDFLARE_BUCKET_DOMAIN=
|
CLOUDFLARE_BUCKET_DOMAIN=
|
||||||
|
|
||||||
@@ -9,11 +11,8 @@ CLOUDFLARE_SECRET_ACCESS_KEY=
|
|||||||
CLOUDFLARE_ACCOUNT_ID=
|
CLOUDFLARE_ACCOUNT_ID=
|
||||||
CLOUDFLARE_BUCKET_ID=
|
CLOUDFLARE_BUCKET_ID=
|
||||||
|
|
||||||
|
# Email
|
||||||
SMTP_HOST=
|
SMTP_HOST=
|
||||||
SMTP_USER=
|
SMTP_USER=
|
||||||
SMTP_PASSWORD=
|
SMTP_PASSWORD=
|
||||||
SMTP_USER_NOTIFY=
|
|
||||||
SMTP_PASSWORD_NOTIFY=
|
|
||||||
SMTP_PORT=
|
SMTP_PORT=
|
||||||
ZOHO_TOKEN=
|
|
||||||
|
|||||||
@@ -3,24 +3,17 @@ const zod = require('zod');
|
|||||||
const { nodemailerTransporter, zohoClient } = require('../utils/email');
|
const { nodemailerTransporter, zohoClient } = require('../utils/email');
|
||||||
const { withEmailTemplate } = require('../utils/withEmailTemplate');
|
const { withEmailTemplate } = require('../utils/withEmailTemplate');
|
||||||
|
|
||||||
const router = express.Router();
|
const emailRouter = express.Router();
|
||||||
|
|
||||||
let personalTransporter;
|
let transporter;
|
||||||
let defaultTransporter;
|
|
||||||
|
|
||||||
// Initialize transporters
|
nodemailerTransporter().then((t) => {
|
||||||
nodemailerTransporter(true).then((t) => {
|
transporter = t;
|
||||||
personalTransporter = t;
|
|
||||||
});
|
|
||||||
nodemailerTransporter(false).then((t) => {
|
|
||||||
defaultTransporter = t;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
async function sendWithNodemailer(emailData) {
|
async function sendWithNodemailer(emailData) {
|
||||||
const { from, to, subject, content, isPersonalEmail, replyTo } = emailData;
|
const { from, to, subject, content, isPersonalEmail, replyTo } = emailData;
|
||||||
|
|
||||||
const transporter = isPersonalEmail ? personalTransporter : defaultTransporter;
|
|
||||||
|
|
||||||
if (!transporter) {
|
if (!transporter) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -73,7 +66,7 @@ async function sendWithZoho(emailData) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
router.post('/', async (req, res) => {
|
emailRouter.post('/', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const mySchema = zod.array(
|
const mySchema = zod.array(
|
||||||
zod.object({
|
zod.object({
|
||||||
@@ -95,7 +88,7 @@ router.post('/', async (req, res) => {
|
|||||||
let res;
|
let res;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (emailData.isPersonalEmail) {
|
if (emailData.isPersonalEmail || !ZOHO_TOKEN) {
|
||||||
res = await sendWithNodemailer(emailData);
|
res = await sendWithNodemailer(emailData);
|
||||||
} else {
|
} else {
|
||||||
res = await sendWithZoho(emailData);
|
res = await sendWithZoho(emailData);
|
||||||
@@ -116,4 +109,4 @@ router.post('/', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = emailRouter;
|
||||||
|
|||||||
@@ -1,29 +1,12 @@
|
|||||||
const { SendMailClient } = require('zeptomail');
|
const { SendMailClient } = require('zeptomail');
|
||||||
const nodemailer = require('nodemailer');
|
const nodemailer = require('nodemailer');
|
||||||
|
|
||||||
const {
|
const { ZOHO_TOKEN, SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASSWORD } = process.env;
|
||||||
ZOHO_TOKEN,
|
|
||||||
SMTP_HOST,
|
|
||||||
SMTP_PORT,
|
|
||||||
SMTP_USER,
|
|
||||||
SMTP_PASSWORD,
|
|
||||||
SMTP_USER_NOTIFY,
|
|
||||||
SMTP_PASSWORD_NOTIFY
|
|
||||||
} = process.env;
|
|
||||||
|
|
||||||
console.log({ ZOHO_TOKEN });
|
|
||||||
|
|
||||||
const zohoClient = new SendMailClient({ url: 'api.zeptomail.eu/', token: ZOHO_TOKEN });
|
const zohoClient = new SendMailClient({ url: 'api.zeptomail.eu/', token: ZOHO_TOKEN });
|
||||||
|
|
||||||
const nodemailerTransporter = async (isPersonal = false) => {
|
const nodemailerTransporter = async () => {
|
||||||
if (
|
if (!SMTP_HOST || !SMTP_PORT || !SMTP_USER || !SMTP_PASSWORD) {
|
||||||
!SMTP_HOST ||
|
|
||||||
!SMTP_PORT ||
|
|
||||||
!SMTP_USER ||
|
|
||||||
!SMTP_PASSWORD ||
|
|
||||||
!SMTP_USER_NOTIFY ||
|
|
||||||
!SMTP_PASSWORD_NOTIFY
|
|
||||||
) {
|
|
||||||
console.error('SMTP configuration missing');
|
console.error('SMTP configuration missing');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -34,8 +17,8 @@ const nodemailerTransporter = async (isPersonal = false) => {
|
|||||||
port: parseInt(SMTP_PORT || '465', 10),
|
port: parseInt(SMTP_PORT || '465', 10),
|
||||||
secure: true,
|
secure: true,
|
||||||
auth: {
|
auth: {
|
||||||
user: isPersonal ? SMTP_USER : SMTP_USER_NOTIFY,
|
user: SMTP_USER,
|
||||||
pass: isPersonal ? SMTP_PASSWORD : SMTP_PASSWORD_NOTIFY
|
pass: SMTP_PASSWORD
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await transporter.verify();
|
await transporter.verify();
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# ClassroomIO
|
||||||
|
# Project: Self-hosted Backend and Dashboard
|
||||||
|
# Description: This docker-compose file sets up the backend and dashboard services for self-hosting.
|
||||||
|
# Author: rotimi-best
|
||||||
|
# Date: 2024-09-18
|
||||||
|
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
backend:
|
||||||
|
image: node:18
|
||||||
|
working_dir: /app
|
||||||
|
volumes:
|
||||||
|
- ./apps/backend:/app
|
||||||
|
command: npm start
|
||||||
|
ports:
|
||||||
|
- '3002:3002'
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
# Supabase - Database
|
||||||
|
- PUBLIC_SUPABASE_ANON_KEY=${PUBLIC_SUPABASE_ANON_KEY}
|
||||||
|
- PUBLIC_SUPABASE_URL=${PUBLIC_SUPABASE_URL}
|
||||||
|
# Cloudflare - Video upload
|
||||||
|
- CLOUDFLARE_BUCKET_DOMAIN=${CLOUDFLARE_BUCKET_DOMAIN}
|
||||||
|
- CLOUDFLARE_ACCESS_KEY=${CLOUDFLARE_ACCESS_KEY}
|
||||||
|
- CLOUDFLARE_SECRET_ACCESS_KEY=${CLOUDFLARE_SECRET_ACCESS_KEY}
|
||||||
|
- CLOUDFLARE_ACCOUNT_ID=${CLOUDFLARE_ACCOUNT_ID}
|
||||||
|
- CLOUDFLARE_BUCKET_ID=${CLOUDFLARE_BUCKET_ID}
|
||||||
|
# SMTP - Emails
|
||||||
|
- SMTP_HOST=${SMTP_HOST}
|
||||||
|
- SMTP_USER=${SMTP_USER}
|
||||||
|
- SMTP_PASSWORD=${SMTP_PASSWORD}
|
||||||
|
- SMTP_PORT=${SMTP_PORT}
|
||||||
|
|
||||||
|
dashboard:
|
||||||
|
image: node:18
|
||||||
|
working_dir: /app
|
||||||
|
volumes:
|
||||||
|
- ./apps/dashboard:/app
|
||||||
|
command: sh -c "npm install -g pnpm && pnpm install && pnpm build && pnpm start"
|
||||||
|
ports:
|
||||||
|
- '5173:5173'
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- IS_SELFHOSTED=true
|
||||||
|
# Supabase - Database
|
||||||
|
- PUBLIC_SUPABASE_URL=${PUBLIC_SUPABASE_URL}
|
||||||
|
- PUBLIC_SUPABASE_ANON_KEY=${PUBLIC_SUPABASE_ANON_KEY}
|
||||||
|
- PRIVATE_SUPABASE_SERVICE_ROLE=${PRIVATE_SUPABASE_SERVICE_ROLE}
|
||||||
|
- PRIVATE_APP_HOST=${PRIVATE_APP_HOST} # yourdomain.com
|
||||||
|
- PRIVATE_APP_SUBDOMAINS=${PRIVATE_APP_SUBDOMAINS} # app (if you are using app.yourdomain.com for the dashboard)
|
||||||
|
- UNSPLASH_API_KEY=${UNSPLASH_API_KEY}
|
||||||
|
- OPENAI_API_KEY=${OPENAI_API_KEY}
|
||||||
|
- PUBLIC_SERVER_URL=${PUBLIC_SERVER_URL} # this is the url to the backend service
|
||||||
|
- PUBLIC_IP_REGISTRY_KEY=${PUBLIC_IP_REGISTRY_KEY}
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
backend_data:
|
||||||
|
dashboard_data:
|
||||||
Reference in New Issue
Block a user