Fix SMTP delivery, add password reset and user deletion

SMTP:
- Add connection/greeting/socket timeouts so a stalled Gmail
  connection no longer hangs sign-up
- Wrap sendMail in try/catch and fall back to logging the code
- Derive secure from port (465 implicit TLS vs 587 STARTTLS)
- Strip whitespace from the Gmail app password
- Document SMTP_HOST/SMTP_PORT in .env.example and environment.d.ts

Password reset (new):
- POST /(api)/auth/forgot-password emails a 6-digit code and does
  not reveal whether the address is registered
- POST /(api)/auth/reset-password validates the code, sets the new
  password, verifies the email, and signs the user in
- password_reset_codes table added to seed-db.mjs
- "Forgot password?" flow on the mobile sign-in screen

User deletion (new):
- DELETE /(api)/admin/users/[id], owner-only, blocks self-deletion
- Delete button with confirmation on the dashboard Users page

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Krikorios
2026-08-23 22:41:41 +03:00
co-authored by Claude Fable 5
parent a0b297285a
commit eceb6b45d5
20 changed files with 899 additions and 206 deletions
+28 -4
View File
@@ -14,12 +14,36 @@ type OAuthProps = {
};
export const OAuth = ({ title }: OAuthProps) => {
const clientId = process.env.EXPO_PUBLIC_GOOGLE_AUTH_WEB_CLIENT_ID;
const iosClientId = process.env.EXPO_PUBLIC_GOOGLE_AUTH_IOS_CLIENT_ID;
const androidClientId =
process.env.EXPO_PUBLIC_GOOGLE_AUTH_ANDROID_CLIENT_ID;
const isConfigured = Boolean(
clientId && (androidClientId || iosClientId),
);
if (!isConfigured) return null;
return <GoogleOAuth title={title} clientId={clientId!} iosClientId={iosClientId} androidClientId={androidClientId} />;
};
function GoogleOAuth({
title,
clientId,
iosClientId,
androidClientId,
}: OAuthProps & {
clientId: string;
iosClientId?: string;
androidClientId?: string;
}) {
const { setSession } = useSession();
const [request, response, promptAsync] = Google.useIdTokenAuthRequest({
clientId: process.env.EXPO_PUBLIC_GOOGLE_AUTH_WEB_CLIENT_ID,
iosClientId: process.env.EXPO_PUBLIC_GOOGLE_AUTH_IOS_CLIENT_ID,
androidClientId: process.env.EXPO_PUBLIC_GOOGLE_AUTH_ANDROID_CLIENT_ID,
clientId,
iosClientId,
androidClientId,
});
useEffect(() => {
@@ -78,4 +102,4 @@ export const OAuth = ({ title }: OAuthProps) => {
/>
</View>
);
};
}