mirror of
https://github.com/temetro/temetro.git
synced 2026-08-10 10:37:43 +00:00
9dabe2f5d2
Implements the first temetro backend: an Express 5 API on Postgres via Drizzle ORM, with authentication and multi-tenant clinics powered by Better Auth. - Auth: email/password with required email verification, password reset, rate limiting, CSRF/trusted-origins, secure cookies, session audit hook. - Organizations (clinics) with RBAC (owner/admin/member/viewer) and an extended `patient` permission set; member invitations by email. - Org-scoped patient records mirroring the frontend Patient shape, with CRUD endpoints gated by permission (read/write/delete). - Email helper logs links to the console when SMTP is unset (zero-setup local dev); Dockerfile + docker-compose (db + backend + frontend) with migrations applied on startup and a configurable Postgres host port. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
50 lines
1.2 KiB
TypeScript
50 lines
1.2 KiB
TypeScript
import nodemailer from "nodemailer";
|
|
|
|
import { env } from "../env.js";
|
|
|
|
type SendArgs = {
|
|
to: string;
|
|
subject: string;
|
|
text: string;
|
|
html?: string;
|
|
};
|
|
|
|
// Lazily build a transport. With SMTP_HOST configured we send real mail;
|
|
// otherwise we fall back to logging the message (and any links) to the
|
|
// server console — zero setup for local / open-source development.
|
|
const transport = env.SMTP_HOST
|
|
? nodemailer.createTransport({
|
|
host: env.SMTP_HOST,
|
|
port: env.SMTP_PORT ?? 587,
|
|
secure: (env.SMTP_PORT ?? 587) === 465,
|
|
auth:
|
|
env.SMTP_USER && env.SMTP_PASS
|
|
? { user: env.SMTP_USER, pass: env.SMTP_PASS }
|
|
: undefined,
|
|
})
|
|
: null;
|
|
|
|
export async function sendEmail({ to, subject, text, html }: SendArgs): Promise<void> {
|
|
if (!transport) {
|
|
console.info(
|
|
[
|
|
"",
|
|
"✉️ [email:console] No SMTP configured — printing instead of sending.",
|
|
` to: ${to}`,
|
|
` subject: ${subject}`,
|
|
` body: ${text}`,
|
|
"",
|
|
].join("\n"),
|
|
);
|
|
return;
|
|
}
|
|
|
|
await transport.sendMail({
|
|
from: env.SMTP_FROM,
|
|
to,
|
|
subject,
|
|
text,
|
|
html: html ?? text,
|
|
});
|
|
}
|