From a1e02173aa90c806fa24e21d09f687e1e7fe3592 Mon Sep 17 00:00:00 2001 From: Rotimi Best Date: Wed, 18 Sep 2024 04:26:24 +0100 Subject: [PATCH] feat: add a docker compose file --- apps/backend/.env.example | 7 ++-- apps/backend/src/routes/sendEmail.js | 21 ++++------ apps/backend/src/utils/email.js | 27 +++--------- docker.compose.yml | 61 ++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 40 deletions(-) create mode 100644 docker.compose.yml diff --git a/apps/backend/.env.example b/apps/backend/.env.example index 04b13d42..abacf469 100644 --- a/apps/backend/.env.example +++ b/apps/backend/.env.example @@ -1,6 +1,8 @@ +## Supabase - DB PUBLIC_SUPABASE_ANON_KEY= PUBLIC_SUPABASE_URL= +## Cloudflare - Video uploads # Not required - https://cdn.example.com CLOUDFLARE_BUCKET_DOMAIN= @@ -9,11 +11,8 @@ CLOUDFLARE_SECRET_ACCESS_KEY= CLOUDFLARE_ACCOUNT_ID= CLOUDFLARE_BUCKET_ID= - +# Email SMTP_HOST= SMTP_USER= SMTP_PASSWORD= -SMTP_USER_NOTIFY= -SMTP_PASSWORD_NOTIFY= SMTP_PORT= -ZOHO_TOKEN= diff --git a/apps/backend/src/routes/sendEmail.js b/apps/backend/src/routes/sendEmail.js index 73358a0a..2bcb760c 100644 --- a/apps/backend/src/routes/sendEmail.js +++ b/apps/backend/src/routes/sendEmail.js @@ -3,24 +3,17 @@ const zod = require('zod'); const { nodemailerTransporter, zohoClient } = require('../utils/email'); const { withEmailTemplate } = require('../utils/withEmailTemplate'); -const router = express.Router(); +const emailRouter = express.Router(); -let personalTransporter; -let defaultTransporter; +let transporter; -// Initialize transporters -nodemailerTransporter(true).then((t) => { - personalTransporter = t; -}); -nodemailerTransporter(false).then((t) => { - defaultTransporter = t; +nodemailerTransporter().then((t) => { + transporter = t; }); async function sendWithNodemailer(emailData) { const { from, to, subject, content, isPersonalEmail, replyTo } = emailData; - const transporter = isPersonalEmail ? personalTransporter : defaultTransporter; - if (!transporter) { return; } @@ -73,7 +66,7 @@ async function sendWithZoho(emailData) { }); } -router.post('/', async (req, res) => { +emailRouter.post('/', async (req, res) => { try { const mySchema = zod.array( zod.object({ @@ -95,7 +88,7 @@ router.post('/', async (req, res) => { let res; try { - if (emailData.isPersonalEmail) { + if (emailData.isPersonalEmail || !ZOHO_TOKEN) { res = await sendWithNodemailer(emailData); } else { res = await sendWithZoho(emailData); @@ -116,4 +109,4 @@ router.post('/', async (req, res) => { } }); -module.exports = router; +module.exports = emailRouter; diff --git a/apps/backend/src/utils/email.js b/apps/backend/src/utils/email.js index 266613e3..2e2d4662 100644 --- a/apps/backend/src/utils/email.js +++ b/apps/backend/src/utils/email.js @@ -1,29 +1,12 @@ const { SendMailClient } = require('zeptomail'); const nodemailer = require('nodemailer'); -const { - ZOHO_TOKEN, - SMTP_HOST, - SMTP_PORT, - SMTP_USER, - SMTP_PASSWORD, - SMTP_USER_NOTIFY, - SMTP_PASSWORD_NOTIFY -} = process.env; - -console.log({ ZOHO_TOKEN }); +const { ZOHO_TOKEN, SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASSWORD } = process.env; const zohoClient = new SendMailClient({ url: 'api.zeptomail.eu/', token: ZOHO_TOKEN }); -const nodemailerTransporter = async (isPersonal = false) => { - if ( - !SMTP_HOST || - !SMTP_PORT || - !SMTP_USER || - !SMTP_PASSWORD || - !SMTP_USER_NOTIFY || - !SMTP_PASSWORD_NOTIFY - ) { +const nodemailerTransporter = async () => { + if (!SMTP_HOST || !SMTP_PORT || !SMTP_USER || !SMTP_PASSWORD) { console.error('SMTP configuration missing'); return null; } @@ -34,8 +17,8 @@ const nodemailerTransporter = async (isPersonal = false) => { port: parseInt(SMTP_PORT || '465', 10), secure: true, auth: { - user: isPersonal ? SMTP_USER : SMTP_USER_NOTIFY, - pass: isPersonal ? SMTP_PASSWORD : SMTP_PASSWORD_NOTIFY + user: SMTP_USER, + pass: SMTP_PASSWORD } }); await transporter.verify(); diff --git a/docker.compose.yml b/docker.compose.yml new file mode 100644 index 00000000..d6c82c71 --- /dev/null +++ b/docker.compose.yml @@ -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: