feat: add duplicate email detection via auth hook with fallback

- Add before-user-created hook function for server-side duplicate email detection
- Implement fallback detection using identities array check (Supabase limitation)
- Update signUpWithPassword to detect duplicate emails via hook errors or empty identities
- Add error handling in login page to show duplicate email errors and auto-switch to login mode
- Add auth hook setup documentation and test scripts
- Add password reset and update password flows
- Add email templates for signup confirmation and password reset
This commit is contained in:
colinislit
2025-11-19 11:03:46 +01:00
parent 114e7d200d
commit 2505b27437
21 changed files with 3671 additions and 201 deletions

52
docs/emails/README.md Normal file
View File

@@ -0,0 +1,52 @@
# Email Templates voor Supabase
Deze directory bevat HTML email templates die gebruikt kunnen worden in Supabase Authentication emails.
## Beschikbare Templates
### 1. `confirm-signup.html`
**Gebruik:** Email bevestiging voor nieuwe gebruikersregistratie
**Supabase variabelen:**
- `{{ .ConfirmationURL }}` - De bevestigingslink die de gebruiker moet klikken
**Waar te gebruiken in Supabase:**
- Authentication → Email Templates → Confirm signup
---
### 2. `reset-password.html`
**Gebruik:** Wachtwoord reset email
**Supabase variabelen:**
- `{{ .ConfirmationURL }}` - De reset link die de gebruiker moet klikken
**Waar te gebruiken in Supabase:**
- Authentication → Email Templates → Reset Password
---
## Hoe te gebruiken in Supabase
1. Log in op je Supabase Dashboard
2. Ga naar **Authentication****Email Templates**
3. Selecteer het juiste template type (Confirm signup of Reset Password)
4. Kopieer de volledige HTML inhoud van het corresponderende `.html` bestand
5. Plak deze in het Supabase email template veld
6. Klik op **Save**
## Design Kenmerken
- **Brand kleur:** Teal (#0D9488) - consistent met AI Speedrun branding
- **Responsive:** Werkt op desktop en mobiel
- **Email client compatibiliteit:** Gebruikt table-based layout voor maximale compatibiliteit
- **Toegankelijkheid:** Goede contrast ratios en duidelijke call-to-action buttons
- **Nederlandse taal:** Alle teksten zijn in het Nederlands
## Aanpassingen
Als je de templates wilt aanpassen:
- Kleuren kunnen worden aangepast in de inline styles (zoek naar `#0D9488` voor de primary kleur)
- Teksten kunnen direct worden aangepast in de HTML
- Let op: Supabase gebruikt Go template syntax (`{{ .VariableName }}`), dus behoud deze variabelen

View File

@@ -0,0 +1,97 @@
<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Bevestig je account - AI Speedrun</title>
<!--[if mso]>
<style type="text/css">
body, table, td {font-family: Arial, sans-serif !important;}
</style>
<![endif]-->
</head>
<body style="margin: 0; padding: 0; background-color: #F8FAFC; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="background-color: #F8FAFC;">
<tr>
<td align="center" style="padding: 40px 20px;">
<!-- Main Container -->
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="600" style="max-width: 600px; background-color: #FFFFFF; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">
<!-- Header -->
<tr>
<td style="padding: 40px 40px 30px; text-align: center; border-bottom: 1px solid #E2E8F0;">
<h1 style="margin: 0; font-size: 24px; font-weight: 600; color: #0F172A; line-height: 1.3;">
Welkom bij AI Speedrun
</h1>
</td>
</tr>
<!-- Content -->
<tr>
<td style="padding: 40px 40px 30px;">
<p style="margin: 0 0 20px; font-size: 16px; line-height: 1.6; color: #475569;">
Leuk dat je meekijkt met deze speedrun!
</p>
<p style="margin: 0 0 30px; font-size: 16px; line-height: 1.6; color: #475569;">
Klik op de onderstaande knop om je emailadres te bevestigen en je account te activeren:
</p>
<!-- CTA Button -->
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<td align="center" style="padding: 0 0 30px;">
<a href="{{ .ConfirmationURL }}" style="display: inline-block; padding: 14px 32px; background-color: #0D9488; color: #FFFFFF; text-decoration: none; border-radius: 6px; font-weight: 500; font-size: 16px; line-height: 1.5;">
Bevestig je account
</a>
</td>
</tr>
</table>
<!-- Alternative Link -->
<p style="margin: 0 0 20px; font-size: 14px; line-height: 1.6; color: #64748B;">
Werkt de knop niet? Kopieer en plak deze link in je browser:
</p>
<p style="margin: 0 0 30px; font-size: 12px; line-height: 1.6; color: #0D9488; word-break: break-all;">
{{ .ConfirmationURL }}
</p>
<!-- Security Note -->
<div style="padding: 16px; background-color: #F0FDFA; border-left: 3px solid #0D9488; border-radius: 4px;">
<p style="margin: 0; font-size: 14px; line-height: 1.6; color: #0F766E;">
<strong>Beveiliging:</strong> Deze link is 24 uur geldig. Als je deze email niet hebt aangevraagd, kun je deze negeren.
</p>
</div>
</td>
</tr>
<!-- Footer -->
<tr>
<td style="padding: 30px 40px 40px; text-align: center; border-top: 1px solid #E2E8F0; background-color: #F8FAFC;">
<p style="margin: 0; font-size: 12px; line-height: 1.6; color: #94A3B8;">
AI Speedrun - Software on Demand<br>
Build in Public door <a href="https://ikbenlit.nl" style="color: #0D9488; text-decoration: none;">AI Speedrun</a>
</p>
</td>
</tr>
</table>
<!-- Bottom Spacing -->
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="600" style="max-width: 600px;">
<tr>
<td style="padding: 20px 0; text-align: center;">
<p style="margin: 0; font-size: 11px; line-height: 1.5; color: #94A3B8;">
Je ontvangt deze email omdat je je hebt geregistreerd voor AI Speedrun.
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>

View File

@@ -0,0 +1,105 @@
<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Wachtwoord opnieuw instellen - AI Speedrun</title>
<!--[if mso]>
<style type="text/css">
body, table, td {font-family: Arial, sans-serif !important;}
</style>
<![endif]-->
</head>
<body style="margin: 0; padding: 0; background-color: #F8FAFC; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="background-color: #F8FAFC;">
<tr>
<td align="center" style="padding: 40px 20px;">
<!-- Main Container -->
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="600" style="max-width: 600px; background-color: #FFFFFF; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">
<!-- Header -->
<tr>
<td style="padding: 40px 40px 30px; text-align: center; border-bottom: 1px solid #E2E8F0;">
<h1 style="margin: 0; font-size: 24px; font-weight: 600; color: #0F172A; line-height: 1.3;">
Wachtwoord opnieuw instellen
</h1>
</td>
</tr>
<!-- Content -->
<tr>
<td style="padding: 40px 40px 30px;">
<p style="margin: 0 0 20px; font-size: 16px; line-height: 1.6; color: #475569;">
Je hebt een verzoek gedaan om je wachtwoord opnieuw in te stellen voor je AI Speedrun account.
</p>
<p style="margin: 0 0 30px; font-size: 16px; line-height: 1.6; color: #475569;">
Klik op de onderstaande knop om een nieuw wachtwoord in te stellen:
</p>
<!-- CTA Button -->
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<td align="center" style="padding: 0 0 30px;">
<a href="{{ .ConfirmationURL }}" style="display: inline-block; padding: 14px 32px; background-color: #0D9488; color: #FFFFFF; text-decoration: none; border-radius: 6px; font-weight: 500; font-size: 16px; line-height: 1.5;">
Wachtwoord opnieuw instellen
</a>
</td>
</tr>
</table>
<!-- Alternative Link -->
<p style="margin: 0 0 20px; font-size: 14px; line-height: 1.6; color: #64748B;">
Werkt de knop niet? Kopieer en plak deze link in je browser:
</p>
<p style="margin: 0 0 30px; font-size: 12px; line-height: 1.6; color: #0D9488; word-break: break-all;">
{{ .ConfirmationURL }}
</p>
<!-- Security Warning -->
<div style="padding: 16px; background-color: #FEF2F2; border-left: 3px solid #DC2626; border-radius: 4px;">
<p style="margin: 0; font-size: 14px; line-height: 1.6; color: #991B1B;">
<strong>Belangrijk:</strong> Als je deze email niet hebt aangevraagd, kun je deze veilig negeren. Je wachtwoord blijft ongewijzigd.
</p>
</div>
<!-- Expiry Note -->
<p style="margin: 20px 0 0; font-size: 14px; line-height: 1.6; color: #64748B;">
Deze link is 1 uur geldig. Na deze tijd moet je een nieuw verzoek indienen.
</p>
</td>
</tr>
<!-- Footer -->
<tr>
<td style="padding: 30px 40px 40px; text-align: center; border-top: 1px solid #E2E8F0; background-color: #F8FAFC;">
<p style="margin: 0 0 12px; font-size: 14px; line-height: 1.6; color: #64748B;">
Vragen over je account? Neem contact met ons op via <a href="mailto:support@aispeedrun.nl" style="color: #0D9488; text-decoration: none;">support@aispeedrun.nl</a>
</p>
<p style="margin: 0; font-size: 12px; line-height: 1.6; color: #94A3B8;">
AI Speedrun - Software on Demand<br>
Build in Public door <a href="https://ikbenlit.nl" style="color: #0D9488; text-decoration: none;">AI Speedrun</a>
</p>
</td>
</tr>
</table>
<!-- Bottom Spacing -->
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="600" style="max-width: 600px;">
<tr>
<td style="padding: 20px 0; text-align: center;">
<p style="margin: 0; font-size: 11px; line-height: 1.5; color: #94A3B8;">
Je ontvangt deze email omdat er een wachtwoord reset is aangevraagd voor je account.
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>