diff --git a/server/landing.ts b/server/landing.ts index 46d8e5de..c38e3578 100644 --- a/server/landing.ts +++ b/server/landing.ts @@ -83,14 +83,14 @@ export function renderMainLanding(modules: ModuleInfo[]): string { - rSpace — Own Your Community Infrastructure - + rSpace — Reclaim (you)rSpace on the Internet + - - + + @@ -98,8 +98,8 @@ export function renderMainLanding(modules: ModuleInfo[]): string { - - + + @@ -131,10 +131,10 @@ export function renderMainLanding(modules: ModuleInfo[]): string {
- Local-first community platform + Reclaim (you)rSpace on the internet

rSpace

- One platform. ${modules.length} apps. All your community’s tools talking to each other. + Coordinate around what you care about — without stitching together a dozen corporate apps.

Start your Space → @@ -161,9 +161,9 @@ export function renderMainLanding(modules: ModuleInfo[]): string {
-

One Platform. Every Tool Connected.

+

Your Group. One Shared Workspace.

- rApps share one sync layer. Data flows automatically — no import/export rituals. + Everything your group needs lives in one place. Data flows between tools automatically — no copy-pasting between apps.

@@ -293,10 +293,10 @@ export function renderMainLanding(modules: ModuleInfo[]): string {
-

Your community. Your rules. Your data.

+

Reclaim (you)rSpace.

No algorithms deciding what you see. No ads. No data harvesting. - Just tools that work for you, run by you, owned by you. + Just one place for your group to plan, decide, fund, and build together.

Start your Space → @@ -609,8 +609,8 @@ body { } .lp-wordmark__r { font-weight: 400; - color: var(--rs-text-primary); - -webkit-text-fill-color: unset; + color: #f97316; + -webkit-text-fill-color: #f97316; } .lp-wordmark__space { background: var(--rs-gradient-brand); diff --git a/server/welcome-email.ts b/server/welcome-email.ts new file mode 100644 index 00000000..1e1c9e48 --- /dev/null +++ b/server/welcome-email.ts @@ -0,0 +1,99 @@ +/** + * Welcome Email — sent once when a user first connects their email address. + */ + +import { getSmtpTransport } from "./notification-service"; + +export async function sendWelcomeEmail(email: string, username: string): Promise { + const transport = await getSmtpTransport(); + if (!transport) { + console.warn("[welcome-email] No SMTP transport available"); + return; + } + + const displayName = username || "there"; + const demoUrl = "https://demo.rspace.online"; + const createUrl = "https://rspace.online/create"; + + const html = ` +
+
+

+ Welcome to rSpace, ${escapeHtml(displayName)}! +

+

+ Reclaim (you)rSpace on the internet — one place for your group to coordinate around what you care about. +

+ +
+

+ Instead of scattering your group across Slack, Google Docs, Trello, Zoom, Splitwise, and a dozen other apps — + (you)rSpace puts it all in one shared workspace that your group actually owns. +

+

+ Plan together. Decide together. Fund together. Build together. No corporate middlemen. +

+
+ +

How groups use rSpace

+ + + + + + + + + + + + + +
+ Plan & Decide
+ Schedule, vote, set priorities — decisions flow into tasks automatically +
+ Create & Share
+ Docs, maps, data — all synced, all encrypted, all yours +
+ Fund & Sustain
+ Shared wallets, resource flows, transparent budgets +
+ Stay Connected
+ Chat, meet, coordinate — without giving your conversations to ad companies +
+ +
+

+ 🔐 Your identity is yours. + One passkey — no passwords, no seeds, no email loops. Works everywhere, owned by nobody but you. +

+
+ + +
+

+ You can manage your email in profile settings at any time. +

+
`; + + try { + await transport.sendMail({ + from: "rSpace ", + to: email, + subject: `Welcome to rSpace, ${displayName} — your group's new home`, + html, + replyTo: "hello@rspace.online", + }); + console.log(`[welcome-email] Sent to ${email}`); + } catch (err: any) { + console.error(`[welcome-email] Failed to send to ${email}:`, err.message); + } +} + +function escapeHtml(s: string): string { + return s.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); +} diff --git a/src/encryptid/server.ts b/src/encryptid/server.ts index e43ad65b..01874e30 100644 --- a/src/encryptid/server.ts +++ b/src/encryptid/server.ts @@ -160,6 +160,7 @@ import { aliasExists, } from './mailcow.js'; import { notify } from '../../server/notification-service'; +import { sendWelcomeEmail } from '../../server/welcome-email'; import { startTrustEngine } from './trust-engine.js'; import { provisionSpaceAlias, syncSpaceAlias, deprovisionSpaceAlias, provisionAgentMailbox, deprovisionAgentMailbox } from './space-alias-service.js'; @@ -1231,9 +1232,15 @@ app.put('/api/user/profile', async (c) => { if (body.profileEmailIsRecovery !== undefined) updates.profileEmailIsRecovery = body.profileEmailIsRecovery; if (body.walletAddress !== undefined) updates.walletAddress = body.walletAddress; + const oldProfile = await getUserProfile(claims.sub as string); const profile = await updateUserProfile(claims.sub as string, updates); if (!profile) return c.json({ error: 'User not found' }, 404); + // Send welcome email on first email connect + if (updates.profileEmail && !oldProfile?.profileEmail) { + sendWelcomeEmail(updates.profileEmail, profile.username).catch(() => {}); + } + // If profile email changed and forwarding is active, update/disable the alias if (updates.profileEmail !== undefined && isMailcowConfigured()) { try {