diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..02f0093 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,237 @@ +# ๐Ÿš€ ๋ฐฐํฌ ๊ฐ€์ด๋“œ + +## 1๏ธโƒฃ Resend ์„ค์ • (์ด๋ฉ”์ผ ๋ฐœ์†ก) + +### 1๋‹จ๊ณ„: Resend ๊ณ„์ • ์ƒ์„ฑ +1. [resend.com](https://resend.com) ์ ‘์† +2. "Sign Up" ํด๋ฆญ โ†’ GitHub ๊ณ„์ •์œผ๋กœ ๊ฐ€์ž… +3. ๋ฌด๋ฃŒ ํ‹ฐ์–ด: ์›” 3,000๊ฑด (์ถฉ๋ถ„ํ•จ!) + +### 2๋‹จ๊ณ„: API Key ๋ฐœ๊ธ‰ +1. Dashboard โ†’ "API Keys" ๋ฉ”๋‰ด +2. "Create API Key" ํด๋ฆญ +3. Name: `jaengseung-made-production` +4. Permission: `Sending access` +5. ์ƒ์„ฑ๋œ ํ‚ค ๋ณต์‚ฌ (ํ•œ ๋ฒˆ๋งŒ ํ‘œ์‹œ๋จ!) + +### 3๋‹จ๊ณ„: ๋„๋ฉ”์ธ ์ธ์ฆ (์„ ํƒ์‚ฌํ•ญ) +**์˜ต์…˜ A: Resend ์„œ๋ธŒ๋„๋ฉ”์ธ ์‚ฌ์šฉ (๊ฐ„๋‹จ)** +- `onboarding@resend.dev`์—์„œ ๋ฐœ์†ก +- ๋ฐ”๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ + +**์˜ต์…˜ B: ์ปค์Šคํ…€ ๋„๋ฉ”์ธ ์‚ฌ์šฉ (์ „๋ฌธ์ )** +1. Resend Dashboard โ†’ "Domains" +2. "Add Domain" ํด๋ฆญ +3. `jaengseung-made.com` ์ž…๋ ฅ +4. DNS ๋ ˆ์ฝ”๋“œ ๋ณต์‚ฌ + +**๊ฐ€๋น„์•„ DNS ์„ค์ •:** +1. [๊ฐ€๋น„์•„ My๊ฐ€๋น„์•„](https://my.gabia.com) ๋กœ๊ทธ์ธ +2. "๋„๋ฉ”์ธ" โ†’ "jaengseung-made.com" ์„ ํƒ +3. "DNS ์ •๋ณด" โ†’ "DNS ๊ด€๋ฆฌ" ํด๋ฆญ +4. Resend์—์„œ ์ œ๊ณตํ•œ ๋ ˆ์ฝ”๋“œ ์ถ”๊ฐ€: + ``` + Type: TXT + Host: _resend + Value: [Resend์—์„œ ์ œ๊ณตํ•œ ๊ฐ’] + + Type: MX + Host: @ + Value: [Resend์—์„œ ์ œ๊ณตํ•œ ๊ฐ’] + Priority: 10 + ``` +5. ์ €์žฅ ํ›„ 10~30๋ถ„ ๋Œ€๊ธฐ +6. Resend์—์„œ "Verify" ํด๋ฆญ + +### 4๋‹จ๊ณ„: ๋กœ์ปฌ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ • +`.env.local` ํŒŒ์ผ ์ˆ˜์ •: +```bash +RESEND_API_KEY=re_your_actual_api_key_here +``` + +--- + +## 2๏ธโƒฃ Vercel ๋ฐฐํฌ + +### 1๋‹จ๊ณ„: GitHub ์—ฐ๋™ (๊ถŒ์žฅ) + +**GitHub์— ํ‘ธ์‹œ:** +```bash +# GitHub์— ์ƒˆ ์ €์žฅ์†Œ ์ƒ์„ฑ (jaengseung-made) +git remote add github https://github.com/your-username/jaengseung-made.git +git push github main +``` + +**Vercel ๋ฐฐํฌ:** +1. [vercel.com](https://vercel.com) ๊ฐ€์ž… (GitHub ์—ฐ๋™) +2. "Add New Project" ํด๋ฆญ +3. GitHub ์ €์žฅ์†Œ ์„ ํƒ: `jaengseung-made` +4. Environment Variables ์ถ”๊ฐ€: + - `RESEND_API_KEY`: [๋ฐœ๊ธ‰๋ฐ›์€ ํ‚ค ๋ถ™์—ฌ๋„ฃ๊ธฐ] +5. "Deploy" ํด๋ฆญ +6. ๋ฐฐํฌ ์™„๋ฃŒ! (์•ฝ 2๋ถ„) + +### 2๋‹จ๊ณ„: ๋„๋ฉ”์ธ ์—ฐ๊ฒฐ (jaengseung-made.com) + +**Vercel ์„ค์ •:** +1. Vercel Dashboard โ†’ ํ”„๋กœ์ ํŠธ ์„ ํƒ +2. "Settings" โ†’ "Domains" +3. "Add Domain" ํด๋ฆญ +4. `jaengseung-made.com` ์ž…๋ ฅ +5. DNS ์„ค์ • ์•ˆ๋‚ด ํ™•์ธ + +**๊ฐ€๋น„์•„ DNS ์„ค์ •:** +1. [๊ฐ€๋น„์•„ My๊ฐ€๋น„์•„](https://my.gabia.com) ๋กœ๊ทธ์ธ +2. "๋„๋ฉ”์ธ" โ†’ "jaengseung-made.com" ์„ ํƒ +3. "DNS ์ •๋ณด" โ†’ "DNS ๊ด€๋ฆฌ" ํด๋ฆญ +4. ๊ธฐ์กด A ๋ ˆ์ฝ”๋“œ ์‚ญ์ œ (์žˆ๋‹ค๋ฉด) +5. ์ƒˆ ๋ ˆ์ฝ”๋“œ ์ถ”๊ฐ€: + +**๋ฐฉ๋ฒ• A: A ๋ ˆ์ฝ”๋“œ (๊ถŒ์žฅ)** +``` +Type: A +Host: @ +Value: 76.76.19.19 +TTL: 600 +``` + +**๋ฐฉ๋ฒ• B: CNAME ๋ ˆ์ฝ”๋“œ** +``` +Type: CNAME +Host: @ +Value: cname.vercel-dns.com. +TTL: 600 +``` + +**www ์„œ๋ธŒ๋„๋ฉ”์ธ ์ถ”๊ฐ€:** +``` +Type: CNAME +Host: www +Value: cname.vercel-dns.com. +TTL: 600 +``` + +6. ์ €์žฅ ํ›„ 10~30๋ถ„ ๋Œ€๊ธฐ +7. Vercel์—์„œ ์ž๋™์œผ๋กœ SSL ์ธ์ฆ์„œ ๋ฐœ๊ธ‰ (HTTPS) + +### 3๋‹จ๊ณ„: ๋ฐฐํฌ ํ™•์ธ +- https://jaengseung-made.com ์ ‘์† +- ๋ฌธ์˜ ํผ ํ…Œ์ŠคํŠธ (์‹ค์ œ ์ด๋ฉ”์ผ ๋ฐœ์†ก ํ™•์ธ) + +--- + +## 3๏ธโƒฃ ๋Œ€์•ˆ: Gitea + Vercel CLI ์ง์ ‘ ๋ฐฐํฌ + +Vercel CLI๋กœ ์ง์ ‘ ๋ฐฐํฌ: +```bash +# Vercel CLI ์„ค์น˜ +npm install -g vercel + +# ํ”„๋กœ์ ํŠธ ํด๋”์—์„œ ์‹คํ–‰ +cd C:\Users\๋ฐ•์žฌ์˜ค\Desktop\workspace\jaengseung-made + +# ๋กœ๊ทธ์ธ +vercel login + +# ๋ฐฐํฌ +vercel --prod + +# ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์ถ”๊ฐ€ +vercel env add RESEND_API_KEY +# [๋ฐœ๊ธ‰๋ฐ›์€ ํ‚ค ๋ถ™์—ฌ๋„ฃ๊ธฐ] +# Production, Preview, Development ๋ชจ๋‘ ์„ ํƒ + +# ์žฌ๋ฐฐํฌ +vercel --prod +``` + +--- + +## 4๏ธโƒฃ Synology NAS ๋ฐฐํฌ (๋น„์ถ”์ฒœ) + +์„ฑ๋Šฅ/์•ˆ์ •์„ฑ ์ด์œ ๋กœ ๋น„์ถ”์ฒœํ•˜์ง€๋งŒ, ์›ํ•˜์‹œ๋ฉด: + +### Docker๋กœ ๋ฐฐํฌ +1. `Dockerfile` ์ƒ์„ฑ (์ด๋ฏธ ์žˆ์Œ) +2. Docker ์ด๋ฏธ์ง€ ๋นŒ๋“œ: +```bash +docker build -t jaengseung-made . +``` +3. ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰: +```bash +docker run -d -p 3000:3000 \ + -e RESEND_API_KEY=your_key \ + --name jaengseung-made \ + jaengseung-made +``` +4. ํฌํŠธ ํฌ์›Œ๋”ฉ: ๋ผ์šฐํ„ฐ์—์„œ 80 โ†’ NAS IP:3000 +5. ๊ฐ€๋น„์•„ DNS: A ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ณต์ธ IP๋กœ ์„ค์ • + +**๋ฌธ์ œ์ :** +- ๋А๋ฆฐ ์†๋„ (๊ฐ€์ •์šฉ ์ธํ„ฐ๋„ท) +- ๋‹ค์šดํƒ€์ž„ (์ •์ „, ์žฌ๋ถ€ํŒ…) +- HTTPS ์ˆ˜๋™ ์„ค์ • ํ•„์š” (Let's Encrypt) +- ๋ณด์•ˆ ๊ด€๋ฆฌ ํ•„์š” + +--- + +## 5๏ธโƒฃ ์ตœ์ข… ์ฒดํฌ๋ฆฌ์ŠคํŠธ + +### ๋ฐฐํฌ ์ „ +- [ ] Resend ๊ณ„์ • ์ƒ์„ฑ ๋ฐ API Key ๋ฐœ๊ธ‰ +- [ ] `.env.local`์— API Key ์„ค์ • +- [ ] ๋กœ์ปฌ์—์„œ ๋ฌธ์˜ ํผ ํ…Œ์ŠคํŠธ (http://localhost:3000) +- [ ] Git ์ปค๋ฐ‹ ๋ฐ ํ‘ธ์‹œ + +### Vercel ๋ฐฐํฌ +- [ ] Vercel ๊ณ„์ • ์ƒ์„ฑ (GitHub ์—ฐ๋™) +- [ ] ํ”„๋กœ์ ํŠธ ๋ฐฐํฌ +- [ ] ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์ถ”๊ฐ€ (RESEND_API_KEY) +- [ ] ๋ฐฐํฌ URL์—์„œ ํ…Œ์ŠคํŠธ + +### ๋„๋ฉ”์ธ ์—ฐ๊ฒฐ +- [ ] Vercel์— ๋„๋ฉ”์ธ ์ถ”๊ฐ€ +- [ ] ๊ฐ€๋น„์•„ DNS ์„ค์ • (A ๋ ˆ์ฝ”๋“œ) +- [ ] www ์„œ๋ธŒ๋„๋ฉ”์ธ ์ถ”๊ฐ€ (CNAME) +- [ ] SSL ์ธ์ฆ์„œ ์ž๋™ ๋ฐœ๊ธ‰ ํ™•์ธ (10~30๋ถ„) +- [ ] https://jaengseung-made.com ์ ‘์† ํ™•์ธ + +### ์ตœ์ข… ํ…Œ์ŠคํŠธ +- [ ] ๋ฌธ์˜ ํผ ์‹ค์ œ ๋ฐœ์†ก ํ…Œ์ŠคํŠธ +- [ ] bgg8988@gmail.com์œผ๋กœ ์ด๋ฉ”์ผ ์ˆ˜์‹  ํ™•์ธ +- [ ] ๋ชจ๋ฐ”์ผ์—์„œ ์ ‘์† ํ…Œ์ŠคํŠธ +- [ ] ๋ชจ๋“  ๋งํฌ ๋™์ž‘ ํ™•์ธ + +### ๋งˆ์ผ€ํŒ… +- [ ] ํฌ๋ชฝ ์„œ๋น„์Šค ๋“ฑ๋ก (ํฌํŠธํด๋ฆฌ์˜ค URL ์ฒจ๋ถ€) +- [ ] ์ˆจ๊ณ  ํ”„๋กœํ•„ ์ƒ์„ฑ +- [ ] Google Search Console ๋“ฑ๋ก +- [ ] ๋ฉ”ํƒ€ ํƒœ๊ทธ ํ™•์ธ (์ด๋ฏธ ์ ์šฉ๋จ) + +--- + +## ๐Ÿ†˜ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… + +### ๋ฌธ์˜ ํผ์ด ์ž‘๋™ํ•˜์ง€ ์•Š์•„์š” +1. `.env.local`์— `RESEND_API_KEY` ํ™•์ธ +2. Vercel ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ • ํ™•์ธ +3. Resend Dashboard์—์„œ "Logs" ํ™•์ธ +4. ๋ธŒ๋ผ์šฐ์ € ๊ฐœ๋ฐœ์ž ๋„๊ตฌ โ†’ Network ํƒญ ํ™•์ธ + +### ๋„๋ฉ”์ธ์ด ์—ฐ๊ฒฐ๋˜์ง€ ์•Š์•„์š” +1. DNS ์ „ํŒŒ ๋Œ€๊ธฐ (์ตœ๋Œ€ 24์‹œ๊ฐ„, ๋ณดํ†ต 30๋ถ„) +2. DNS ์ „ํŒŒ ํ™•์ธ: https://dnschecker.org +3. ๊ฐ€๋น„์•„ DNS ์„ค์ • ์žฌํ™•์ธ +4. Vercel Domain ์ƒํƒœ ํ™•์ธ + +### ์ด๋ฉ”์ผ์ด ์˜ค์ง€ ์•Š์•„์š” +1. Resend Dashboard โ†’ "Logs" ํ™•์ธ +2. ์ŠคํŒธ ๋ฉ”์ผํ•จ ํ™•์ธ +3. API Key ๊ถŒํ•œ ํ™•์ธ (Sending access) +4. ๋„๋ฉ”์ธ ์ธ์ฆ ์ƒํƒœ ํ™•์ธ (์ปค์Šคํ…€ ๋„๋ฉ”์ธ ์‚ฌ์šฉ ์‹œ) + +--- + +## ๐Ÿ“ž ์ง€์› + +๋ฐฐํฌ ๊ด€๋ จ ๋ฌธ์˜: bgg8988@gmail.com diff --git a/app/api/contact/route.ts b/app/api/contact/route.ts new file mode 100644 index 0000000..6ffadb2 --- /dev/null +++ b/app/api/contact/route.ts @@ -0,0 +1,52 @@ +import { NextResponse } from 'next/server'; +import { Resend } from 'resend'; + +const resend = new Resend(process.env.RESEND_API_KEY); + +export async function POST(request: Request) { + try { + const body = await request.json(); + const { name, phone, email, service, message } = body; + + // ์ž…๋ ฅ ๊ฒ€์ฆ + if (!name || !email || !message) { + return NextResponse.json( + { error: 'ํ•„์ˆ˜ ํ•ญ๋ชฉ์„ ๋ชจ๋‘ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.' }, + { status: 400 } + ); + } + + // ์ด๋ฉ”์ผ ๋ฐœ์†ก + const data = await resend.emails.send({ + from: 'contact@jaengseung-made.com', // Resend์—์„œ ์ธ์ฆ๋œ ๋„๋ฉ”์ธ + to: ['bgg8988@gmail.com'], // ๋ฐ›๋Š” ์ด๋ฉ”์ผ + subject: `[์Ÿ์Šน๋ฉ”์ด๋“œ] ์ƒˆ๋กœ์šด ๋ฌธ์˜: ${service || '๋ฌธ์˜'}`, + html: ` +

์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ ๋ฌธ์˜๊ฐ€ ๋„์ฐฉํ–ˆ์Šต๋‹ˆ๋‹ค

+
+

์ด๋ฆ„: ${name}

+

์—ฐ๋ฝ์ฒ˜: ${phone || '๋ฏธ์ž…๋ ฅ'}

+

์ด๋ฉ”์ผ: ${email}

+

์„œ๋น„์Šค: ${service || '๋ฏธ์„ ํƒ'}

+
+

๋ฌธ์˜ ๋‚ด์šฉ:

+

${message}

+
+

+ ์ด ๋ฉ”์ผ์€ jaengseung-made.com์˜ ๋ฌธ์˜ ํผ์—์„œ ๋ฐœ์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค. +

+ `, + }); + + return NextResponse.json( + { success: true, message: '๋ฌธ์˜๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ „์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค!' }, + { status: 200 } + ); + } catch (error) { + console.error('Email send error:', error); + return NextResponse.json( + { error: '๋ฉ”์ผ ์ „์†ก์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.' }, + { status: 500 } + ); + } +} diff --git a/app/components/ContactForm.tsx b/app/components/ContactForm.tsx new file mode 100644 index 0000000..fee32c2 --- /dev/null +++ b/app/components/ContactForm.tsx @@ -0,0 +1,186 @@ +'use client'; + +import { useState } from 'react'; + +export default function ContactForm() { + const [formData, setFormData] = useState({ + name: '', + phone: '', + email: '', + service: 'RPA ์ž๋™ํ™”', + message: '', + }); + const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle'); + const [errorMessage, setErrorMessage] = useState(''); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setStatus('loading'); + setErrorMessage(''); + + try { + const response = await fetch('/api/contact', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(formData), + }); + + const data = await response.json(); + + if (!response.ok) { + throw new Error(data.error || '๋ฌธ์˜ ์ „์†ก์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.'); + } + + setStatus('success'); + // ํผ ์ดˆ๊ธฐํ™” + setFormData({ + name: '', + phone: '', + email: '', + service: 'RPA ์ž๋™ํ™”', + message: '', + }); + + // 3์ดˆ ํ›„ ์„ฑ๊ณต ๋ฉ”์‹œ์ง€ ์ˆจ๊ธฐ๊ธฐ + setTimeout(() => setStatus('idle'), 5000); + } catch (error) { + setStatus('error'); + setErrorMessage(error instanceof Error ? error.message : '๋ฌธ์˜ ์ „์†ก์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.'); + } + }; + + const handleChange = ( + e: React.ChangeEvent + ) => { + setFormData((prev) => ({ + ...prev, + [e.target.name]: e.target.value, + })); + }; + + return ( +
+
+
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + {status === 'success' && ( +
+ โœ… ๋ฌธ์˜๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ „์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค! 24์‹œ๊ฐ„ ์ด๋‚ด ๋‹ต๋ณ€๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค. +
+ )} + + {status === 'error' && ( +
+ โŒ {errorMessage} +
+ )} + + +
+ +
+
+

๋˜๋Š” ์•„๋ž˜ ์—ฐ๋ฝ์ฒ˜๋กœ ์ง์ ‘ ๋ฌธ์˜์ฃผ์„ธ์š”

+
+ + ๐Ÿ“ง bgg8988@gmail.com + + + ๐Ÿ“ฑ 010-3907-1392 + +
+
+
+
+ ); +} diff --git a/app/page.tsx b/app/page.tsx index f0c4541..0b1b7f7 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,3 +1,5 @@ +import ContactForm from './components/ContactForm'; + export default function Home() { return (
@@ -331,77 +333,7 @@ export default function Home() {

๋ฌด์—‡์ด๋“  ํŽธํ•˜๊ฒŒ ์ƒ๋‹ดํ•ด์ฃผ์„ธ์š”. 24์‹œ๊ฐ„ ์ด๋‚ด ๋‹ต๋ณ€๋“œ๋ฆฝ๋‹ˆ๋‹ค.

-
-
-
-
- - -
-
- - -
-
- -
- - -
- -
- - -
- -
- - -
- - -
- -
-
-

๋˜๋Š” ์•„๋ž˜ ์—ฐ๋ฝ์ฒ˜๋กœ ์ง์ ‘ ๋ฌธ์˜์ฃผ์„ธ์š”

-
- - ๐Ÿ“ง bgg8988@gmail.com - - - ๐Ÿ“ฑ 010-3907-1392 - -
-
-
-
+ diff --git a/package-lock.json b/package-lock.json index 101564d..d640cfa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,8 @@ "dependencies": { "next": "16.1.6", "react": "19.2.3", - "react-dom": "19.2.3" + "react-dom": "19.2.3", + "resend": "^6.9.1" }, "devDependencies": { "@tailwindcss/postcss": "^4", @@ -1233,6 +1234,25 @@ "dev": true, "license": "MIT" }, + "node_modules/@selderee/plugin-htmlparser2": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz", + "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==", + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "selderee": "^0.11.0" + }, + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, + "node_modules/@stablelib/base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", + "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==", + "license": "MIT" + }, "node_modules/@swc/helpers": { "version": "0.5.15", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", @@ -2113,6 +2133,17 @@ "win32" ] }, + "node_modules/@zone-eu/mailsplit": { + "version": "5.4.8", + "resolved": "https://registry.npmjs.org/@zone-eu/mailsplit/-/mailsplit-5.4.8.tgz", + "integrity": "sha512-eEyACj4JZ7sjzRvy26QhLgKEMWwQbsw1+QZnlLX+/gihcNH07lVPOcnwf5U6UAL7gkc//J3jVd76o/WS+taUiA==", + "license": "(MIT OR EUPL-1.1+)", + "dependencies": { + "libbase64": "1.3.0", + "libmime": "5.3.7", + "libqp": "2.1.1" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -2718,6 +2749,15 @@ "dev": true, "license": "MIT" }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -2777,6 +2817,61 @@ "node": ">=0.10.0" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -2806,6 +2901,15 @@ "dev": true, "license": "MIT" }, + "node_modules/encoding-japanese": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/encoding-japanese/-/encoding-japanese-2.2.0.tgz", + "integrity": "sha512-EuJWwlHPZ1LbADuKTClvHtwbaFn4rOD+dRAbWysqEOXRc2Uui0hJInNJrsdH0c+OhJA4nrCBdSkW4DD5YxAo6A==", + "license": "MIT", + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.19.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", @@ -2820,6 +2924,18 @@ "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-abstract": { "version": "1.24.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", @@ -3495,6 +3611,12 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-sha256": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz", + "integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==", + "license": "Unlicense" + }, "node_modules/fastq": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", @@ -3873,6 +3995,15 @@ "node": ">= 0.4" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, "node_modules/hermes-estree": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", @@ -3890,6 +4021,57 @@ "hermes-estree": "0.25.1" } }, + "node_modules/html-to-text": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz", + "integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==", + "license": "MIT", + "dependencies": { + "@selderee/plugin-htmlparser2": "^0.11.0", + "deepmerge": "^4.3.1", + "dom-serializer": "^2.0.0", + "htmlparser2": "^8.0.2", + "selderee": "^0.11.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -4512,6 +4694,15 @@ "node": ">=0.10" } }, + "node_modules/leac": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz", + "integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==", + "license": "MIT", + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4526,6 +4717,42 @@ "node": ">= 0.8.0" } }, + "node_modules/libbase64": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.3.0.tgz", + "integrity": "sha512-GgOXd0Eo6phYgh0DJtjQ2tO8dc0IVINtZJeARPeiIJqge+HdsWSuaDTe8ztQ7j/cONByDZ3zeB325AHiv5O0dg==", + "license": "MIT" + }, + "node_modules/libmime": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.7.tgz", + "integrity": "sha512-FlDb3Wtha8P01kTL3P9M+ZDNDWPKPmKHWaU/cG/lg5pfuAwdflVpZE+wm9m7pKmC5ww6s+zTxBKS1p6yl3KpSw==", + "license": "MIT", + "dependencies": { + "encoding-japanese": "2.2.0", + "iconv-lite": "0.6.3", + "libbase64": "1.3.0", + "libqp": "2.1.1" + } + }, + "node_modules/libmime/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/libqp": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/libqp/-/libqp-2.1.1.tgz", + "integrity": "sha512-0Wd+GPz1O134cP62YU2GTOPNA7Qgl09XwCqM5zpBv87ERCXdfDtyKXvV7c9U22yWJh44QZqBocFnXN11K96qow==", + "license": "MIT" + }, "node_modules/lightningcss": { "version": "1.30.2", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", @@ -4787,6 +5014,15 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -4843,6 +5079,24 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/mailparser": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.9.1.tgz", + "integrity": "sha512-6vHZcco3fWsDMkf4Vz9iAfxvwrKNGbHx0dV1RKVphQ/zaNY34Buc7D37LSa09jeSeybWzYcTPjhiZFxzVRJedA==", + "license": "MIT", + "dependencies": { + "@zone-eu/mailsplit": "5.4.8", + "encoding-japanese": "2.2.0", + "he": "1.2.0", + "html-to-text": "9.0.5", + "iconv-lite": "0.7.0", + "libmime": "5.3.7", + "linkify-it": "5.0.0", + "nodemailer": "7.0.11", + "punycode.js": "2.3.1", + "tlds": "1.261.0" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -5036,6 +5290,15 @@ "dev": true, "license": "MIT" }, + "node_modules/nodemailer": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.11.tgz", + "integrity": "sha512-gnXhNRE0FNhD7wPSCGhdNh46Hs6nm+uTyg+Kq0cZukNQiYdnCsoQjodNP9BQVG9XrcK/v6/MgpAPBUFyzh9pvw==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -5240,6 +5503,19 @@ "node": ">=6" } }, + "node_modules/parseley": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz", + "integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==", + "license": "MIT", + "dependencies": { + "leac": "^0.6.0", + "peberminta": "^0.9.0" + }, + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -5267,6 +5543,15 @@ "dev": true, "license": "MIT" }, + "node_modules/peberminta": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz", + "integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==", + "license": "MIT", + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -5357,6 +5642,15 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -5450,6 +5744,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resend": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/resend/-/resend-6.9.1.tgz", + "integrity": "sha512-jFY3qPP2cith1npRXvS7PVdnhbR1CcuzHg65ty5Elv55GKiXhe+nItXuzzoOlKeYJez1iJAo2+8f6ae8sCj0iA==", + "license": "MIT", + "dependencies": { + "mailparser": "3.9.1", + "svix": "1.84.1" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@react-email/render": "*" + }, + "peerDependenciesMeta": { + "@react-email/render": { + "optional": true + } + } + }, "node_modules/resolve": { "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", @@ -5581,12 +5896,30 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, + "node_modules/selderee": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz", + "integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==", + "license": "MIT", + "dependencies": { + "parseley": "^0.12.0" + }, + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -5819,6 +6152,16 @@ "dev": true, "license": "MIT" }, + "node_modules/standardwebhooks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.0.0.tgz", + "integrity": "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==", + "license": "MIT", + "dependencies": { + "@stablelib/base64": "^1.0.0", + "fast-sha256": "^1.3.0" + } + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -6018,6 +6361,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svix": { + "version": "1.84.1", + "resolved": "https://registry.npmjs.org/svix/-/svix-1.84.1.tgz", + "integrity": "sha512-K8DPPSZaW/XqXiz1kEyzSHYgmGLnhB43nQCMeKjWGCUpLIpAMMM8kx3rVVOSm6Bo6EHyK1RQLPT4R06skM/MlQ==", + "license": "MIT", + "dependencies": { + "standardwebhooks": "1.0.0", + "uuid": "^10.0.0" + } + }, "node_modules/tailwindcss": { "version": "4.1.18", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", @@ -6087,6 +6440,15 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/tlds": { + "version": "1.261.0", + "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.261.0.tgz", + "integrity": "sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA==", + "license": "MIT", + "bin": { + "tlds": "bin.js" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -6274,6 +6636,12 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", @@ -6376,6 +6744,19 @@ "punycode": "^2.1.0" } }, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 991bc2a..d4961b9 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "dependencies": { "next": "16.1.6", "react": "19.2.3", - "react-dom": "19.2.3" + "react-dom": "19.2.3", + "resend": "^6.9.1" }, "devDependencies": { "@tailwindcss/postcss": "^4",