feat: add Resend email + encryption key + initial user to provision flow
All checks were successful
Build & Release / build (push) Successful in 13s
All checks were successful
Build & Release / build (push) Successful in 13s
- RESEND_API_KEY added to config (required env var) - Provision generates per-customer ENCRYPTION_KEY and patches lunarfront-secrets with resend-api-key, mail-from, business-name, encryption-key - initialEmail field in ProvisionSchema seeds first admin user via env vars on app first boot Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ export const config = {
|
|||||||
cfApiToken: process.env.CF_API_TOKEN!,
|
cfApiToken: process.env.CF_API_TOKEN!,
|
||||||
cfZoneId: process.env.CF_ZONE_ID!,
|
cfZoneId: process.env.CF_ZONE_ID!,
|
||||||
ingressIp: process.env.INGRESS_IP ?? "167.99.21.170",
|
ingressIp: process.env.INGRESS_IP ?? "167.99.21.170",
|
||||||
|
resendApiKey: process.env.RESEND_API_KEY!,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const [key, val] of Object.entries(config)) {
|
for (const [key, val] of Object.entries(config)) {
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ const ProvisionSchema = z.object({
|
|||||||
modules: z.array(z.enum(MODULES)).default([]),
|
modules: z.array(z.enum(MODULES)).default([]),
|
||||||
startDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).default(() => new Date().toISOString().slice(0, 10)),
|
startDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).default(() => new Date().toISOString().slice(0, 10)),
|
||||||
expirationDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().default(null),
|
expirationDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().default(null),
|
||||||
|
initialEmail: z.object({
|
||||||
|
email: z.string().email(),
|
||||||
|
password: z.string().min(12).max(128),
|
||||||
|
firstName: z.string().min(1).max(100),
|
||||||
|
lastName: z.string().min(1).max(100),
|
||||||
|
}).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const ListQuerySchema = z.object({
|
const ListQuerySchema = z.object({
|
||||||
@@ -128,12 +134,23 @@ export async function customerRoutes(app: FastifyInstance) {
|
|||||||
await setStep("namespace", "done");
|
await setStep("namespace", "done");
|
||||||
await setStep("secrets", "done");
|
await setStep("secrets", "done");
|
||||||
|
|
||||||
|
const encryptionKey = crypto.randomBytes(32).toString("hex");
|
||||||
await patchSecret(namespace, "lunarfront-secrets", {
|
await patchSecret(namespace, "lunarfront-secrets", {
|
||||||
"spaces-key": config.spacesKey,
|
"spaces-key": config.spacesKey,
|
||||||
"spaces-secret": config.spacesSecret,
|
"spaces-secret": config.spacesSecret,
|
||||||
"spaces-bucket": config.spacesBucket,
|
"spaces-bucket": config.spacesBucket,
|
||||||
"spaces-endpoint": `https://${config.spacesRegion}.digitaloceanspaces.com`,
|
"spaces-endpoint": `https://${config.spacesRegion}.digitaloceanspaces.com`,
|
||||||
"spaces-prefix": `${slug}/`,
|
"spaces-prefix": `${slug}/`,
|
||||||
|
"encryption-key": encryptionKey,
|
||||||
|
"resend-api-key": config.resendApiKey,
|
||||||
|
"mail-from": `noreply@${slug}.lunarfront.tech`,
|
||||||
|
"business-name": body.name,
|
||||||
|
...(body.initialEmail ? {
|
||||||
|
"initial-user-email": body.initialEmail.email,
|
||||||
|
"initial-user-password": body.initialEmail.password,
|
||||||
|
"initial-user-first-name": body.initialEmail.firstName,
|
||||||
|
"initial-user-last-name": body.initialEmail.lastName,
|
||||||
|
} : {}),
|
||||||
});
|
});
|
||||||
await setStep("storage", "done");
|
await setStep("storage", "done");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user