From d062df14aab65b1d59639758ce56d8eb1cf80f5f Mon Sep 17 00:00:00 2001 From: Harshith Mullapudi Date: Wed, 27 Aug 2025 22:44:32 +0530 Subject: [PATCH] fix: emails are not sent on welcome --- .../components/spaces/space-pattern-card.tsx | 12 +- apps/webapp/app/models/workspace.server.ts | 5 +- apps/webapp/app/routes/api.v1.search.tsx | 7 +- .../app/routes/confirm-basic-details.tsx | 10 +- apps/webapp/app/services/email.server.ts | 10 +- apps/webapp/app/trigger/chat/chat.ts | 9 +- apps/webapp/app/trigger/extension/search.ts | 14 ++- apps/webapp/app/trigger/utils/utils.ts | 2 +- packages/emails/emails/components/Footer.tsx | 12 +- packages/emails/emails/components/styles.ts | 45 ++++--- packages/emails/emails/welcome.tsx | 111 +++++++++++------- packages/emails/src/index.tsx | 8 +- packages/emails/src/transports/resend.ts | 15 +-- turbo.json | 7 +- 14 files changed, 166 insertions(+), 101 deletions(-) diff --git a/apps/webapp/app/components/spaces/space-pattern-card.tsx b/apps/webapp/app/components/spaces/space-pattern-card.tsx index e61201f..a278d87 100644 --- a/apps/webapp/app/components/spaces/space-pattern-card.tsx +++ b/apps/webapp/app/components/spaces/space-pattern-card.tsx @@ -22,7 +22,7 @@ export function SpacePatternCard({ pattern }: SpacePatternCardProps) { actionType, patternId: pattern.id, }, - { method: "POST" } + { method: "POST" }, ); setDialog(false); }; @@ -77,19 +77,19 @@ export function SpacePatternCard({ pattern }: SpacePatternCardProps) {
- -
diff --git a/apps/webapp/app/models/workspace.server.ts b/apps/webapp/app/models/workspace.server.ts index d9cb78d..76d9125 100644 --- a/apps/webapp/app/models/workspace.server.ts +++ b/apps/webapp/app/models/workspace.server.ts @@ -1,5 +1,6 @@ import { type Workspace } from "@core/database"; import { prisma } from "~/db.server"; +import { sendEmail } from "~/services/email.server"; import { SpaceService } from "~/services/space.server"; interface CreateWorkspaceDto { @@ -31,7 +32,7 @@ export async function createWorkspace( }, }); - await prisma.user.update({ + const user = await prisma.user.update({ where: { id: input.userId }, data: { confirmedBasicDetails: true, @@ -45,6 +46,8 @@ export async function createWorkspace( workspaceId: workspace.id, }); + await sendEmail({ email: "welcome", to: user.email }); + return workspace; } diff --git a/apps/webapp/app/routes/api.v1.search.tsx b/apps/webapp/app/routes/api.v1.search.tsx index ad1553f..ddf3b3c 100644 --- a/apps/webapp/app/routes/api.v1.search.tsx +++ b/apps/webapp/app/routes/api.v1.search.tsx @@ -1,5 +1,8 @@ import { z } from "zod"; -import { createActionApiRoute } from "~/services/routeBuilders/apiBuilder.server"; +import { + createActionApiRoute, + createHybridActionApiRoute, +} from "~/services/routeBuilders/apiBuilder.server"; import { SearchService } from "~/services/search.server"; import { json } from "@remix-run/node"; @@ -19,7 +22,7 @@ export const SearchBodyRequest = z.object({ }); const searchService = new SearchService(); -const { action, loader } = createActionApiRoute( +const { action, loader } = createHybridActionApiRoute( { body: SearchBodyRequest, allowJWT: true, diff --git a/apps/webapp/app/routes/confirm-basic-details.tsx b/apps/webapp/app/routes/confirm-basic-details.tsx index 2653034..44e82ea 100644 --- a/apps/webapp/app/routes/confirm-basic-details.tsx +++ b/apps/webapp/app/routes/confirm-basic-details.tsx @@ -1,5 +1,5 @@ import { z } from "zod"; -import { useActionData, useLoaderData } from "@remix-run/react"; +import { useActionData } from "@remix-run/react"; import { type ActionFunctionArgs, json, @@ -17,12 +17,7 @@ import { } from "~/components/ui/card"; import { Button } from "~/components/ui"; import { Input } from "~/components/ui/input"; -import { useState } from "react"; -import { - requireUser, - requireUserId, - requireWorkpace, -} from "~/services/session.server"; +import { requireUser, requireUserId } from "~/services/session.server"; import { redirectWithSuccessMessage } from "~/models/message.server"; import { rootPath } from "~/utils/pathBuilder"; import { createWorkspace, getWorkspaceByUser } from "~/models/workspace.server"; @@ -76,7 +71,6 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { export default function ConfirmBasicDetails() { const lastSubmission = useActionData(); - const { workspace } = useLoaderData(); const [form, fields] = useForm({ lastSubmission: lastSubmission as any, diff --git a/apps/webapp/app/services/email.server.ts b/apps/webapp/app/services/email.server.ts index feecd5e..55e2190 100644 --- a/apps/webapp/app/services/email.server.ts +++ b/apps/webapp/app/services/email.server.ts @@ -16,8 +16,8 @@ const client = singleton( new EmailClient({ transport: buildTransportOptions(), imagesBaseUrl: env.APP_ORIGIN, - from: env.FROM_EMAIL ?? "Harshith ", - replyTo: env.REPLY_TO_EMAIL ?? "harshith@tegon.ai", + from: env.FROM_EMAIL ?? "Manik ", + replyTo: env.REPLY_TO_EMAIL ?? "manik@poozle.dev", }), ); @@ -85,5 +85,9 @@ export async function scheduleEmail( ) {} export async function sendEmail(data: DeliverEmail) { - return client.send(data); + try { + return client.send(data); + } catch (e) { + logger.error(`Error: ${e}`); + } } diff --git a/apps/webapp/app/trigger/chat/chat.ts b/apps/webapp/app/trigger/chat/chat.ts index 99de2fc..f72b5eb 100644 --- a/apps/webapp/app/trigger/chat/chat.ts +++ b/apps/webapp/app/trigger/chat/chat.ts @@ -6,6 +6,7 @@ import { MCP } from "../utils/mcp"; import { type HistoryStep } from "../utils/types"; import { createConversationHistoryForAgent, + deletePersonalAccessToken, getCreditsForUser, getPreviousExecutionHistory, init, @@ -120,9 +121,15 @@ export const chat = task({ ); usageCredits && (await updateUserCredits(usageCredits, 1)); + + if (init?.tokenId) { + await deletePersonalAccessToken(init.tokenId); + } } catch (e) { await updateConversationStatus("failed", payload.conversationId); - + if (init?.tokenId) { + await deletePersonalAccessToken(init.tokenId); + } throw new Error(e as string); } }, diff --git a/apps/webapp/app/trigger/extension/search.ts b/apps/webapp/app/trigger/extension/search.ts index 78b5a94..8e0be5a 100644 --- a/apps/webapp/app/trigger/extension/search.ts +++ b/apps/webapp/app/trigger/extension/search.ts @@ -4,8 +4,12 @@ import { z } from "zod"; import { openai } from "@ai-sdk/openai"; import { logger } from "~/services/logger.service"; -import { getOrCreatePersonalAccessToken } from "../utils/utils"; +import { + deletePersonalAccessToken, + getOrCreatePersonalAccessToken, +} from "../utils/utils"; import axios from "axios"; +import { nanoid } from "nanoid"; export const ExtensionSearchBodyRequest = z.object({ userInput: z.string().min(1, "User input is required"), @@ -24,8 +28,10 @@ export const extensionSearch = task({ const { userInput, userId, context } = ExtensionSearchBodyRequest.parse(body); + const randomKeyName = `extensionSearch_${nanoid(10)}`; + const pat = await getOrCreatePersonalAccessToken({ - name: "extensionSearch", + name: randomKeyName, userId: userId as string, }); @@ -106,8 +112,12 @@ If no relevant information is found, provide a brief statement indicating that.` finalText = finalText + chunk; } + await deletePersonalAccessToken(pat?.id); + return finalText; } catch (error) { + await deletePersonalAccessToken(pat?.id); + logger.error(`SearchMemoryAgent error: ${error}`); return `Context related to: ${userInput}. Looking for relevant background information, previous discussions, and related concepts that would help provide a comprehensive answer.`; diff --git a/apps/webapp/app/trigger/utils/utils.ts b/apps/webapp/app/trigger/utils/utils.ts index da3279c..18a9699 100644 --- a/apps/webapp/app/trigger/utils/utils.ts +++ b/apps/webapp/app/trigger/utils/utils.ts @@ -170,7 +170,7 @@ export const init = async ({ payload }: { payload: InitChatPayload }) => { return { conversation, conversationHistory }; } - const randomKeyName = `chat`; + const randomKeyName = `chat_${nanoid(10)}`; const pat = await getOrCreatePersonalAccessToken({ name: randomKeyName, userId: workspace.userId as string, diff --git a/packages/emails/emails/components/Footer.tsx b/packages/emails/emails/components/Footer.tsx index 0c8cef4..a046eac 100644 --- a/packages/emails/emails/components/Footer.tsx +++ b/packages/emails/emails/components/Footer.tsx @@ -1,16 +1,16 @@ -import { Hr, Link, Text } from "@react-email/components"; +import { Hr, Text } from "@react-email/components"; import React from "react"; -import { footer, footerAnchor, hr } from "./styles"; +import { footer, hr, paragraphLight } from "./styles"; export function Footer() { return ( <>
+ happy building your digital brain! - ©Sol.ai - - C.O.R.E - + the Core team P.S Questions? +
+ Just hit reply - we're here to help.
); diff --git a/packages/emails/emails/components/styles.ts b/packages/emails/emails/components/styles.ts index 6c07873..e7ca8c5 100644 --- a/packages/emails/emails/components/styles.ts +++ b/packages/emails/emails/components/styles.ts @@ -8,10 +8,7 @@ export const h1 = { padding: "0", }; -export const main = { - backgroundColor: "#15171A", - padding: "0 20px", -}; +export const main = {}; export const container = { backgroundColor: "#15171A", @@ -30,29 +27,42 @@ export const hr = { }; export const paragraph = { - color: "#878C99", + color: "black", fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif', - fontSize: "16px", + fontSize: "14px", lineHeight: "24px", textAlign: "left" as const, }; export const paragraphLight = { - color: "#D7D9DD", + color: "black", fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif', - fontSize: "16px", + fontSize: "14px", lineHeight: "24px", textAlign: "left" as const, + margin: 0, +}; + +export const heading = { + color: "black", + fontFamily: + '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif', + fontSize: "14px", + lineHeight: "24px", + textAlign: "left" as const, + fontWeight: "bold", + margin: 0, + marginTop: "20px", }; export const paragraphTight = { - color: "#D7D9DD", + color: "black", fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif', - fontSize: "16px", - lineHeight: "16px", + fontSize: "14px", + lineHeight: "14px", textAlign: "left" as const, }; @@ -60,18 +70,19 @@ export const bullets = { color: "#D7D9DD", fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif', - fontSize: "16px", + fontSize: "14px", lineHeight: "24px", textAlign: "left" as const, margin: "0", }; export const anchor = { - color: "#826DFF", + marginRight: "3px", fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif", - fontSize: "16px", + fontSize: "14px", textDecoration: "underline", + color: "black", }; export const button = { @@ -80,7 +91,7 @@ export const button = { color: "#D7D9DD", fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif', - fontSize: "16px", + fontSize: "14px", fontWeight: "bold", textDecoration: "none", textAlign: "center" as const, @@ -92,7 +103,7 @@ export const footer = { fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif', fontSize: "12px", - lineHeight: "16px", + lineHeight: "14px", }; export const footerItalic = { @@ -101,7 +112,7 @@ export const footerItalic = { fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif', fontSize: "12px", - lineHeight: "16px", + lineHeight: "14px", }; export const footerAnchor = { diff --git a/packages/emails/emails/welcome.tsx b/packages/emails/emails/welcome.tsx index abd2880..76a2bdf 100644 --- a/packages/emails/emails/welcome.tsx +++ b/packages/emails/emails/welcome.tsx @@ -1,59 +1,86 @@ -import { Body, Head, Html, Link, Preview, Section, Text } from "@react-email/components"; +import { Body, Head, Html, Img, Link, Preview, Text } from "@react-email/components"; import { Footer } from "./components/Footer"; -import { anchor, bullets, footerItalic, main, paragraphLight } from "./components/styles"; +import { anchor, heading, main, paragraphLight } from "./components/styles"; import { z } from "zod"; export const WelcomeEmailSchema = z.object({ email: z.literal("welcome"), - orgName: z.string(), - inviterName: z.string().optional(), - inviterEmail: z.string(), - inviteLink: z.string().url(), }); -export function WelcomeEmail({ orgName }: { orgName?: string }) { +export default function WelcomeEmail() { return ( - Welcome to C.O.R.E. - Your Personal AI Assistant + building your digital brain - Hey {orgName ?? "there"}, - Welcome to C.O.R.E., your new personal AI assistant! - - I'm excited to help you streamline your daily tasks, boost your productivity, and make - your work life easier. C.O.R.E. is designed to be intuitive and powerful, adapting to your - unique needs and preferences. - - - To get started, you can{" "} - - visit your dashboard - {" "} - where you'll find all the features and capabilities at your disposal. Whether it's - managing your schedule, handling communications, or automating repetitive tasks, I'm here - to help. - - - - If you have any questions or need assistance, don't hesitate to reach out. You can:{"\n"}• - Ask me directly through the chat interface{"\n"}•{" "} - - Visit our support center + hi there, + + + Manik - {"\n"}• Join our{" "} - - Discord community - {" "} - to connect with other users and our team + from core here. welcome to core. when i first tried core memory, two actions made it click + for me. each came down to the same thing: understanding how I can add relevant context + about everything that matters to me in core memory and recall it wherever I want. + core mcp + + seamlessly add your code context from cursor/claude-code, project context from linear, or + brainstorming sessions from claude desktop via mcp. solve context loss problems across ai + tools with persistent, cross-session memory. add this url and get started + + + https://core.heysol.ai/api/v1/mcp?source='Your Coding Agent' + + Claude + browser extension + + recall relevant context from core memory in chatgpt, grok, and gemini. save conversations + and content from chatgpt, grok, gemini, twitter, youtube, blog posts, and any webpage + directly into your Core memory with simple text selection. + + Claude - Looking forward to being your trusted assistant! - - Best regards, - C.O.R.E. - Your AI Assistant - - You can customize your notification preferences anytime in your account settings. + need real-time, human help to get started? + + - join our discord community & get direct help from our team + over 100+ enthusiasts using + Core memory + + + - We are open-source us on our repo -{" "} + + https://github.com/RedPlanetHQ/core +