feat(db): mesh data model — meshes, members, invites, audit log
- pgSchema "mesh" with 4 tables isolating the peer mesh domain - Enums: visibility, transport, tier, role - audit_log is metadata-only (E2E encryption enforced at broker/client) - Cascade on mesh delete, soft-delete via archivedAt/revokedAt Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,391 @@
|
||||
---
|
||||
title: Configuration
|
||||
description: Learn how to configure your emails in TurboStarter.
|
||||
url: /docs/web/emails/configuration
|
||||
---
|
||||
|
||||
# Configuration
|
||||
|
||||
The `@turbostarter/email` package provides a simple and flexible way to send emails using various email providers. It abstracts the complexity of different email services and offers a consistent interface for sending emails with pre-defined templates.
|
||||
|
||||
To configure the email service, you need to set an `EMAIL_FROM` environment variable. It will be used as the sender of the emails. **Please make sure that the mail address and domain are verified in your mail provider.**
|
||||
|
||||
```dotenv
|
||||
EMAIL_FROM="hello@resend.dev"
|
||||
```
|
||||
|
||||
The email provider is configured by modifying the exports in `packages/email` package. By default, [Nodemailer](/docs/web/emails/configuration#nodemailer) is used.
|
||||
|
||||
Configuration will be validated against the schema, so you will see the error messages in the console if something is not right.
|
||||
|
||||
## Providers
|
||||
|
||||
TurboStarter supports multiple email providers, each with its own configuration. Below, you'll find detailed information on how to set up and use each supported provider. Choose the one that best fits your needs and follow the instructions in the respective accordion section.
|
||||
|
||||
<Accordions>
|
||||
<Accordion title="Resend" id="resend">
|
||||
To use Resend as your email provider, you need to [create an account](https://resend.com/) and [obtain your API key](https://resend.com/docs/dashboard/api-keys/introduction).
|
||||
|
||||
Then, set it as an environment variable in your `.env.local` file in `apps/web` directory and your deployment environment:
|
||||
|
||||
```dotenv
|
||||
RESEND_API_KEY="your-api-key"
|
||||
```
|
||||
|
||||
Also, make sure to activate Resend as your email provider by updating the exports in:
|
||||
|
||||
<Tabs items={["index.ts", "env.ts"]}>
|
||||
<Tab value="index.ts">
|
||||
```ts
|
||||
// [!code word:resend]
|
||||
export * from "./resend";
|
||||
```
|
||||
</Tab>
|
||||
|
||||
<Tab value="env.ts">
|
||||
```ts
|
||||
// [!code word:resend]
|
||||
export * from "./resend/env";
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
To customize the provider, you can find its definition in `packages/email/src/providers/resend` directory.
|
||||
|
||||
For more information, please refer to the [Resend documentation](https://resend.com/docs).
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="SendGrid" id="sendgrid">
|
||||
To use SendGrid as your email provider, you need to [create an account](https://sendgrid.com/) and [obtain your API key](https://sendgrid.com/docs/ui/account-and-settings/api-keys/).
|
||||
|
||||
Then, set it as an environment variable in your `.env.local` file in `apps/web` directory and your deployment environment:
|
||||
|
||||
```dotenv
|
||||
SENDGRID_API_KEY="your-api-key"
|
||||
```
|
||||
|
||||
Also, make sure to activate SendGrid as your email provider by updating the exports in:
|
||||
|
||||
<Tabs items={["index.ts", "env.ts"]}>
|
||||
<Tab value="index.ts">
|
||||
```ts
|
||||
// [!code word:sendgrid]
|
||||
export * from "./sendgrid";
|
||||
```
|
||||
</Tab>
|
||||
|
||||
<Tab value="env.ts">
|
||||
```ts
|
||||
// [!code word:sendgrid]
|
||||
export * from "./sendgrid/env";
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
To customize the provider, you can find its definition in `packages/email/src/providers/sendgrid` directory.
|
||||
|
||||
For more information, please refer to the [SendGrid documentation](https://sendgrid.com/docs).
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Postmark" id="postmark">
|
||||
To use Postmark as your email provider, you need to [create an account](https://postmarkapp.com/) and [obtain your server API token](https://postmarkapp.com/support/article/1008-what-are-the-account-and-server-api-tokens).
|
||||
|
||||
Then, set it as an environment variable in your `.env.local` file in `apps/web` directory and your deployment environment:
|
||||
|
||||
```dotenv
|
||||
POSTMARK_API_KEY="your-secret-api-token"
|
||||
```
|
||||
|
||||
Also, make sure to activate Postmark as your email provider by updating the exports in:
|
||||
|
||||
<Tabs items={["index.ts", "env.ts"]}>
|
||||
<Tab value="index.ts">
|
||||
```ts
|
||||
export * from "./postmark";
|
||||
```
|
||||
</Tab>
|
||||
|
||||
<Tab value="env.ts">
|
||||
```ts
|
||||
// [!code word:postmark]
|
||||
export * from "./postmark/env";
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
To customize the provider, you can find its definition in `packages/email/src/providers/postmark` directory.
|
||||
|
||||
For more information, please refer to the [Postmark documentation](https://postmarkapp.com/developer).
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Plunk" id="plunk">
|
||||
To use Plunk as your email provider, you need to [create an account](https://plunk.dev/) and [obtain your API key](https://docs.useplunk.com/api-reference/authentication).
|
||||
|
||||
Then, set it as an environment variable in your `.env.local` file in `apps/web` directory and your deployment environment:
|
||||
|
||||
```dotenv
|
||||
PLUNK_API_KEY="your-api-key"
|
||||
```
|
||||
|
||||
Also, make sure to activate Plunk as your email provider by updating the exports in:
|
||||
|
||||
<Tabs items={["index.ts", "env.ts"]}>
|
||||
<Tab value="index.ts">
|
||||
```ts
|
||||
// [!code word:plunk]
|
||||
export * from "./plunk";
|
||||
```
|
||||
</Tab>
|
||||
|
||||
<Tab value="env.ts">
|
||||
```ts
|
||||
// [!code word:plunk]
|
||||
export * from "./plunk/env";
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
To customize the provider, you can find its definition in `packages/email/src/providers/plunk` directory.
|
||||
|
||||
For more information, please refer to the [Plunk documentation](https://docs.useplunk.com).
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="nodemailer" id="nodemailer">
|
||||
If you're using the `nodemailer` as your email provider, you'll need to set the following SMTP configuration in your environment variables:
|
||||
|
||||
```dotenv
|
||||
NODEMAILER_HOST="your-smtp-host"
|
||||
NODEMAILER_PORT="your-smtp-port"
|
||||
NODEMAILER_USER="your-smtp-user"
|
||||
NODEMAILER_PASSWORD="your-smtp-password"
|
||||
```
|
||||
|
||||
The variables are:
|
||||
|
||||
* `NODEMAILER_HOST`: The host of your SMTP server.
|
||||
* `NODEMAILER_PORT`: The port of your SMTP server.
|
||||
* `NODEMAILER_USER`: The email address user of your SMTP server.
|
||||
* `NODEMAILER_PASSWORD`: The password for the email account.
|
||||
|
||||
Also, make sure to activate nodemailer as your email provider by updating the exports in:
|
||||
|
||||
<Tabs items={["index.ts", "env.ts"]}>
|
||||
<Tab value="index.ts">
|
||||
```ts
|
||||
// [!code word:nodemailer]
|
||||
export * from "./nodemailer";
|
||||
```
|
||||
</Tab>
|
||||
|
||||
<Tab value="env.ts">
|
||||
```ts
|
||||
// [!code word:nodemailer]
|
||||
export * from "./nodemailer/env";
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
To customize the provider, you can find its definition in `packages/email/src/providers/nodemailer` directory.
|
||||
|
||||
For more information, please refer to the [nodemailer documentation](https://nodemailer.com/smtp/).
|
||||
</Accordion>
|
||||
</Accordions>
|
||||
|
||||
## Templates
|
||||
|
||||
In the `@turbostarter/email` package, we provide a set of pre-defined templates for you to use. You can find them in the `packages/email/src/templates` directory.
|
||||
|
||||
When you run your development server, you will be able to preview all available templates in the browser under [http://localhost:3005](http://localhost:3005).
|
||||
|
||||

|
||||
|
||||
Next to the templates, you can also find some shared components that you can use in your emails. The file structure looks like this:
|
||||
|
||||
<Files>
|
||||
<Folder name="templates" defaultOpen>
|
||||
<Folder name="_components - Shared components used in emails" />
|
||||
|
||||
<Folder name="auth - Authentication related emails" />
|
||||
|
||||
<File name="index.ts - Main entrypoint for the templates" />
|
||||
</Folder>
|
||||
</Files>
|
||||
|
||||
Feel free to add your own templates and components or modify existing ones to match them with your brand and style.
|
||||
|
||||
### How to add a new template?
|
||||
|
||||
We'll go through the process of adding a new template, as it requires a few steps to make sure everything works correctly.
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
#### Define types
|
||||
|
||||
Let's assume that we want to add a **welcome email**, that new users will receive after signing up.
|
||||
|
||||
We'll start with defining new template type in `packages/email/src/types/templates.ts` file:
|
||||
|
||||
```ts title="templates.ts"
|
||||
export const EmailTemplate = {
|
||||
...AuthEmailTemplate,
|
||||
WELCOME: "welcome",
|
||||
} as const;
|
||||
```
|
||||
|
||||
Also, we would need to add types for variables that we'll pass to the template (if any), in our case it will be just a `name` of the user:
|
||||
|
||||
```ts title="templates.ts"
|
||||
type WelcomeEmailVariables = {
|
||||
welcome: {
|
||||
name: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type EmailVariables = AuthEmailVariables | WelcomeEmailVariables;
|
||||
```
|
||||
|
||||
By doing this, we ensure that payload passed to the template will have all required properties and we won't end up with an email that tells your user "Hey, undefined!".
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
#### Create template
|
||||
|
||||
Next up, we need to create a file with the template itself. We'll create an `welcome.tsx` file in `packages/email/src/templates` directory.
|
||||
|
||||
```tsx title="welcome.tsx"
|
||||
import { Heading, Preview, Text } from "@react-email/components";
|
||||
|
||||
import { Button } from "../_components/button";
|
||||
import { Layout } from "../_components/layout/layout";
|
||||
|
||||
import type { EmailTemplate, EmailVariables } from "../../types";
|
||||
|
||||
type Props = EmailVariables[typeof EmailTemplate.WELCOME];
|
||||
|
||||
export const Welcome = ({ name }: Props) => {
|
||||
return (
|
||||
<Layout>
|
||||
<Preview>Welcome to TurboStarter!</Preview>
|
||||
<Heading>Hi, {name}!</Heading>
|
||||
|
||||
<Text>Start your journey with our app by clicking the button below.</Text>
|
||||
|
||||
<Button>Start</Button>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
Welcome.subject = "Welcome to TurboStarter!";
|
||||
|
||||
Welcome.PreviewProps = {
|
||||
name: "John Doe",
|
||||
};
|
||||
|
||||
export default Welcome;
|
||||
```
|
||||
|
||||
As you can see, by defining appropriate types for the template, we can safely use the variables as a props in the template.
|
||||
|
||||
To learn more about supported components, please refer to the [React Email documentation](https://react.email/docs/components).
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
#### Register template
|
||||
|
||||
We have to register the template in the main entrypoint of the templates in `packages/email/src/templates/index.ts` file:
|
||||
|
||||
```ts title="index.ts"
|
||||
import { Welcome } from "./welcome";
|
||||
|
||||
export const templates = {
|
||||
...
|
||||
[EmailTemplate.WELCOME]: Welcome,
|
||||
} as const;
|
||||
```
|
||||
|
||||
That way, it will be available in the `sendEmail` function, enabling us to send it from the server-side of your application.
|
||||
|
||||
```ts
|
||||
import { sendEmail } from "@turbostarter/email/server";
|
||||
|
||||
sendEmail({
|
||||
to: "user@example.com",
|
||||
template: EmailTemplate.WELCOME,
|
||||
variables: {
|
||||
name: "John Doe",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Learn more about sending emails in the [dedicated section](/docs/web/emails/sending).
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
Et voilà! You've just added a new email template to your application 🎉
|
||||
|
||||
### Translating templates
|
||||
|
||||
You can also translate your templates to support multiple languages. Each mail template is passed the `locale` property, which you can use to get the translation for the current locale. This allows you to maintain consistent translations across your application and emails.
|
||||
|
||||
The translation system [uses the same i18n setup](/docs/web/internationalization/overview) as your main application, so you can reuse your existing translation files and namespaces. The translations are loaded server-side when the email is generated, ensuring the correct language is used based on the user's preferences.
|
||||
|
||||
Here's how you can implement translations in your email templates:
|
||||
|
||||
```tsx
|
||||
import { Heading, Preview, Text } from "@react-email/components";
|
||||
|
||||
import { getTranslation } from "@turbostarter/i18n/server";
|
||||
|
||||
import { Button } from "../_components/button";
|
||||
import { Layout } from "../_components/layout/layout";
|
||||
|
||||
import type {
|
||||
EmailTemplate,
|
||||
EmailVariables,
|
||||
CommonEmailProps,
|
||||
} from "../../types";
|
||||
|
||||
type Props = EmailVariables[typeof EmailTemplate.WELCOME] & CommonEmailProps;
|
||||
|
||||
export const Welcome = async ({ name, locale }: Props) => {
|
||||
const { t } = await getTranslation({ locale, ns: "auth" });
|
||||
|
||||
return (
|
||||
<Layout locale={locale}>
|
||||
<Preview>{t("account.welcome.preview")}</Preview>
|
||||
<Heading>{t("account.welcome.heading", { name })}</Heading>
|
||||
|
||||
<Text>{t("account.welcome.body")}</Text>
|
||||
|
||||
<Button>{t("account.welcome.cta")}</Button>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
Welcome.subject = async ({ locale }: CommonEmailProps) => {
|
||||
const { t } = await getTranslation({ locale, ns: "auth" });
|
||||
return t("account.welcome.subject");
|
||||
};
|
||||
|
||||
Welcome.PreviewProps = {
|
||||
name: "John Doe",
|
||||
locale: "en",
|
||||
};
|
||||
|
||||
export default Welcome;
|
||||
```
|
||||
|
||||
To send the email in the specified language, you can pass the optional `locale` argument to the `sendEmail` function:
|
||||
|
||||
```ts
|
||||
sendEmail({
|
||||
to: "user@example.com",
|
||||
template: EmailTemplate.WELCOME,
|
||||
variables: {
|
||||
name: "John Doe",
|
||||
},
|
||||
locale: "en", // [!code highlight]
|
||||
});
|
||||
```
|
||||
|
||||
Learn more about translations in the [dedicated section](/docs/web/internationalization/translations).
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
title: Overview
|
||||
description: Get started with emails in TurboStarter.
|
||||
url: /docs/web/emails/overview
|
||||
---
|
||||
|
||||
# Overview
|
||||
|
||||
For mailing functionality, TurboStarter integrates [React Email](https://react.email/docs/introduction) which enables you to build your emails from composable React components.
|
||||
|
||||
<Callout title="Why React Email?">
|
||||
It's a simple, yet powerful library that allows you to **write your emails in React**.
|
||||
|
||||
It also allows you to use **Tailwind CSS for styling**, which is a huge advantage, as we can share almost everything from the main app with the emails package, keeping them consistent with rest of the app.
|
||||
</Callout>
|
||||
|
||||
You can read more about `react-email` package in the [official documentation](https://react.email/docs/introduction).
|
||||
|
||||
## Providers
|
||||
|
||||
TurboStarter implements multiple providers for managing and sending emails. To learn more about each provider and how to configure them, see the respective section:
|
||||
|
||||
<Cards>
|
||||
<Card title="Resend" href="/docs/web/emails/configuration#resend" />
|
||||
|
||||
<Card title="SendGrid" href="/docs/web/emails/configuration#sendgrid" />
|
||||
|
||||
<Card title="Postmark" href="/docs/web/emails/configuration#postmark" />
|
||||
|
||||
<Card title="Plunk" href="/docs/web/emails/configuration#plunk" />
|
||||
|
||||
<Card title="Nodemailer" href="/docs/web/emails/configuration#nodemailer" />
|
||||
</Cards>
|
||||
|
||||
All configuration and setup is built-in with a unified API, so you can switch between providers by simply changing the exports and even introduce your own provider without breaking any sending-related logic.
|
||||
|
||||
## Development
|
||||
|
||||
When you [setup your development environment](/docs/web/installation/development) and run `pnpm dev` command a new app will start at [http://localhost:3005](http://localhost:3005).
|
||||
|
||||

|
||||
|
||||
There you'll be able to check your email templates and send test emails from your app. It includes hot-reloading, so when you make change in the code - it will be reflected in the browser.
|
||||
|
||||
Learn more about configuration and setup of the emails in TurboStarter in the following sections.
|
||||
@@ -0,0 +1,114 @@
|
||||
---
|
||||
title: Sending emails
|
||||
description: Learn how to send emails in TurboStarter.
|
||||
url: /docs/web/emails/sending
|
||||
---
|
||||
|
||||
# Sending emails
|
||||
|
||||
The strategy for sending emails, that every provider has to implement, is **extremely simple**:
|
||||
|
||||
```ts
|
||||
export interface EmailProviderStrategy {
|
||||
send: (args: {
|
||||
to: string;
|
||||
subject: string;
|
||||
text: string;
|
||||
html?: string;
|
||||
}) => Promise<void>;
|
||||
}
|
||||
```
|
||||
|
||||
<Callout>
|
||||
You don't need to worry much about it, as all the providers are already configured for you. Just be aware of it if you want to add your custom provider.
|
||||
</Callout>
|
||||
|
||||
Then, we define a general `sendEmail` function that you can use as an API for sending emails in your app:
|
||||
|
||||
```ts
|
||||
const sendEmail = async <T extends EmailTemplate>({
|
||||
to,
|
||||
template,
|
||||
variables,
|
||||
locale,
|
||||
}: {
|
||||
to: string;
|
||||
template: T;
|
||||
variables: EmailVariables[T];
|
||||
locale?: string;
|
||||
}) => {
|
||||
const { html, text, subject } = await getTemplate({
|
||||
id: template,
|
||||
variables,
|
||||
locale,
|
||||
});
|
||||
|
||||
return send({ to, subject, html, text });
|
||||
};
|
||||
```
|
||||
|
||||
The arguments are:
|
||||
|
||||
* `to`: The recipient's email address.
|
||||
* `template`: The email template to use.
|
||||
* `variables`: The variables to pass to the template.
|
||||
* `locale`: The locale to use for the email.
|
||||
|
||||
It returns a promise that resolves when the email is sent successfully. If there is an error, the promise will be rejected with an error message.
|
||||
|
||||
To send an email, just invoke the `sendEmail` with the correct arguments from the **server-side** of your application:
|
||||
|
||||
```ts
|
||||
import { sendEmail } from "@turbostarter/email/server";
|
||||
|
||||
sendEmail({
|
||||
to: "user@example.com",
|
||||
template: EmailTemplate.WELCOME,
|
||||
variables: {
|
||||
name: "John Doe",
|
||||
},
|
||||
locale: "en",
|
||||
});
|
||||
```
|
||||
|
||||
And that's it! You're ready to send emails in your application 🚀
|
||||
|
||||
## Authentication emails
|
||||
|
||||
TurboStarter comes with a set of pre-configured authentication emails for various purposes, including magic links and password reset functionality.
|
||||
|
||||
To handle the sending of these emails at the right time, we use [Better Auth Hooks](https://www.better-auth.com/docs/concepts/email), which trigger when specific authentication events occur.
|
||||
|
||||
The logic for determining which email to send is already implemented for you in the `packages/auth/src/server.ts` file, alongside your [authentication configuration](/docs/web/auth/configuration):
|
||||
|
||||
```ts title="server.ts"
|
||||
export const auth = betterAuth({
|
||||
emailAndPassword: {
|
||||
enabled: true,
|
||||
sendResetPassword: async ({ user, url }) =>
|
||||
sendEmail({
|
||||
to: user.email,
|
||||
template: EmailTemplate.RESET_PASSWORD,
|
||||
variables: {
|
||||
url,
|
||||
},
|
||||
}),
|
||||
},
|
||||
emailVerification: {
|
||||
sendVerificationEmail: async ({ user, url }) =>
|
||||
sendEmail({
|
||||
to: user.email,
|
||||
template: EmailTemplate.CONFIRM_EMAIL,
|
||||
variables: {
|
||||
url,
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
/* other options */
|
||||
});
|
||||
```
|
||||
|
||||
As you can see, the authentication emails are automatically sent when needed (e.g. when user requests password reset or needs to verify their email address).
|
||||
|
||||
You can customize authentication templates by modifying them in the `packages/email/src/templates` directory, or create your own templates for other use cases in your application.
|
||||
Reference in New Issue
Block a user