From 57d2c43da705ddcb044b9249fc2e2f5025aa2215 Mon Sep 17 00:00:00 2001 From: Eric Gullickson <16152721+ericgullickson@users.noreply.github.com> Date: Sun, 28 Dec 2025 16:56:36 -0600 Subject: [PATCH] fix: Email template improvements --- backend/Dockerfile | 19 +++-- .../domain/email-layout/base-layout.ts | 85 +++++++++++++++++++ .../domain/email-layout/email-styles.ts | 39 +++++++++ .../notifications/domain/email.service.ts | 14 +-- .../domain/notifications.service.ts | 22 +++-- .../notifications/domain/template.service.ts | 35 ++++++++ .../005_update_email_templates_html.sql | 16 ++++ docker-compose.yml | 4 +- docs/PROMPTS.md | 26 +++--- frontend/src/features/admin/api/admin.api.ts | 9 +- .../AdminEmailTemplatesMobileScreen.tsx | 51 +++++++++-- .../src/features/admin/types/admin.types.ts | 6 ++ .../pages/admin/AdminEmailTemplatesPage.tsx | 63 +++++++++++--- 13 files changed, 325 insertions(+), 64 deletions(-) create mode 100644 backend/src/features/notifications/domain/email-layout/base-layout.ts create mode 100644 backend/src/features/notifications/domain/email-layout/email-styles.ts create mode 100644 backend/src/features/notifications/migrations/005_update_email_templates_html.sql diff --git a/backend/Dockerfile b/backend/Dockerfile index 833ecd2..5362640 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -9,16 +9,21 @@ RUN apk add --no-cache dumb-init git curl # Set working directory WORKDIR /app -# Copy package files -COPY package*.json ./ +# Copy package files from backend directory +COPY backend/package*.json ./ # Install all dependencies (including dev for building) RUN npm install && npm cache clean --force -# Copy source code -COPY . . +# Copy logo from frontend for email templates (needed for build) +RUN mkdir -p frontend/public/images/logos +COPY frontend/public/images/logos/motovaultpro-logo-title.png frontend/public/images/logos/ -# Build the application +# Copy backend source code +COPY backend/ . + +# Build the application (prebuild will encode logo) +ENV DOCKER_BUILD=true RUN npm run build # Stage 2: Production runtime @@ -31,7 +36,7 @@ RUN apk add --no-cache dumb-init curl postgresql-client WORKDIR /app # Copy package files and any lock file generated in builder stage -COPY package*.json ./ +COPY backend/package*.json ./ COPY --from=builder /app/package-lock.json ./ # Install only production dependencies @@ -52,7 +57,7 @@ COPY --from=builder /app/src/features /app/migrations/features COPY --from=builder /app/src/core /app/migrations/core # Copy entrypoint script for permission checks -COPY scripts/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh +COPY backend/scripts/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh RUN chmod 755 /usr/local/bin/docker-entrypoint.sh # Change ownership to non-root user diff --git a/backend/src/features/notifications/domain/email-layout/base-layout.ts b/backend/src/features/notifications/domain/email-layout/base-layout.ts new file mode 100644 index 0000000..2322cb6 --- /dev/null +++ b/backend/src/features/notifications/domain/email-layout/base-layout.ts @@ -0,0 +1,85 @@ +/** + * Base HTML Email Layout + * @ai-summary Main email wrapper with MotoVaultPro branding + * @ai-context Uses table-based layout for email client compatibility + */ + +import { EMAIL_STYLES } from './email-styles'; + +// External logo URL - hosted on GitHub for reliability +const LOGO_URL = 'https://raw.githubusercontent.com/ericgullickson/images/c58b0e4773e8395b532f97f6ab529e38ea4dc8be/motovaultpro-auth0-small.png'; + +/** + * Renders the complete HTML email layout with branding + * @param content - The rendered email body content (HTML) + * @returns Complete HTML email string with DOCTYPE and layout + */ +export function renderEmailLayout(content: string): string { + return ` + +
+ + + + +
+
+
|
+
${line}
`).join(''); - await this.send(to, subject, html); - } } diff --git a/backend/src/features/notifications/domain/notifications.service.ts b/backend/src/features/notifications/domain/notifications.service.ts index 5ccfbe9..550a162 100644 --- a/backend/src/features/notifications/domain/notifications.service.ts +++ b/backend/src/features/notifications/domain/notifications.service.ts @@ -94,10 +94,15 @@ export class NotificationsService { subject: string, body: string, variables: Record${escapeHtml(line)}
`) + .join('\n'); + + // 4. Wrap in branded email layout + return renderEmailLayout(htmlContent); + } + /** * Extract variable names from a template string * @param template Template string with {{variable}} placeholders diff --git a/backend/src/features/notifications/migrations/005_update_email_templates_html.sql b/backend/src/features/notifications/migrations/005_update_email_templates_html.sql new file mode 100644 index 0000000..4688e8c --- /dev/null +++ b/backend/src/features/notifications/migrations/005_update_email_templates_html.sql @@ -0,0 +1,16 @@ +/** + * Migration: Add HTML body column to email templates + * @ai-summary Non-breaking migration for future HTML template support + * @ai-context Existing plain text templates auto-convert to HTML + */ + +-- Add optional html_body column for custom HTML templates (future enhancement) +ALTER TABLE email_templates +ADD COLUMN html_body TEXT DEFAULT NULL; + +-- Add comment explaining the column purpose +COMMENT ON COLUMN email_templates.html_body IS + 'Optional custom HTML body. If NULL, the plain text body will be auto-converted to HTML with base layout.'; + +-- No data updates needed - existing templates continue to work +-- The system will auto-convert plain text body to HTML using renderEmailHtml() diff --git a/docker-compose.yml b/docker-compose.yml index d2d0121..b3ce799 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -86,8 +86,8 @@ services: # Application Services - Backend API mvp-backend: build: - context: ./backend - dockerfile: Dockerfile + context: . + dockerfile: backend/Dockerfile cache_from: - node:lts-alpine container_name: mvp-backend diff --git a/docs/PROMPTS.md b/docs/PROMPTS.md index 01dc660..5594580 100644 --- a/docs/PROMPTS.md +++ b/docs/PROMPTS.md @@ -48,16 +48,19 @@ You are a senior software engineer specializsing in NodeJS, Typescript, front en - Make no assumptions. - Ask clarifying questions. - Ultrathink -- The initial data load for this applicaiton during the CI/CD process in gitlab needs to be updated +- This application is ready to go into production. +- Analysis needs to be done on the CI/CD pipeline *** CONTEXT *** - Read README.md CLAUDE.md and AI-INDEX.md and follow relevant instructions to understand this code repository in the context of this change. -- The current deployment database load needs to be thoroughly critiqued and scrutenized. +- The current deployment does not take into account no downtime or miniimal downtime updates. +- The same runner's build the software that run the software +- There needs to be a balance of uptime and complexity +- production will run on a single server to start *** ACTION - CHANGES TO IMPLEMENT *** -- The vehicle catalog currently loaded into the local mvp-postres container needs to be exported into a SQL file and saved as a source of truth -- Whatever process is running today only goes up to model year 2022. -- All the existing SQL files setup for import can be replaced with new ones created from the running mvp-postres data. +- Research this code base and ask iterative questions to compile a complete plan. +- We will pair plan this. Ask me for options for various levels of redundancy and automation @@ -100,14 +103,17 @@ You are a senior software engineer specializsing in NodeJS, Typescript, front en - Make no assumptions. - Ask clarifying questions. - Ultrathink -- You will be making changes to the color theme of this application. +- You will be making changes to email templates of this application. *** CONTEXT *** - This is a modern web app for managing a vehicle fleet. It has both a desktop and mobile versions of the site that both need to maintain feature parity. It's currently deployed via docker compose but in the future will be deployed via k8s. - Read README.md CLAUDE.md and AI-INDEX.md and follow relevant instructions to understand this code repository in the context of this change. -- Currently the onboarding drop downs are washed out when using the light theme. See image. -- The colors need to change to have more contrast but retain the MUI theme for drop down. +- Start your research at this route https://motovaultpro.com/garage/settings/admin/email-templates +- The email templates are currently plain text. +- The templates need to be improved with colors and the company logo +- The company log should be base64 encoded in the email so end users don't need to download anything. +- The theme should match the website light theme +- A screenshot showing the colors is attached *** CHANGES TO IMPLEMENT *** -- Research this code base and ask iterative questions to compile a complete plan. -- The URL is here. https://motovaultpro.com/onboarding \ No newline at end of file +- Research this code base and ask iterative questions to compile a complete plan. \ No newline at end of file diff --git a/frontend/src/features/admin/api/admin.api.ts b/frontend/src/features/admin/api/admin.api.ts index 4c2bd48..f68307a 100644 --- a/frontend/src/features/admin/api/admin.api.ts +++ b/frontend/src/features/admin/api/admin.api.ts @@ -30,6 +30,7 @@ import { CascadeDeleteResult, EmailTemplate, UpdateEmailTemplateRequest, + PreviewTemplateResponse, // User management types ManagedUser, ListUsersResponse, @@ -278,15 +279,15 @@ export const adminApi = { const response = await apiClient.put