# Story 1-8: Contact Page with Form (聯絡頁面與表單) **Status:** ready-for-dev **Epic:** Epic 1 - Webflow to Payload CMS + Astro Migration **Priority:** P1 (High - Key conversion page) **Estimated Time:** 6-8 hours **Dependencies:** Story 1.4 (Global Layout Components) --- ## Story **作為** 潛在客戶, **我想要** 透過表單聯絡恩群數位, **這樣** 我就能詢問他們的服務並開始合作。 ## Context 這是一個關鍵的轉換頁面!聯絡表單是潛在客戶與恩群數位建立關係的第一步。我們需要建立一個功能完整、視覺吸引且用戶友善的聯絡頁面,表單提交透過 Cloudflare Worker 處理並發送 Email 通知。 **Story Source:** - `docs/prd/05-epic-stories.md` - Story 1.8 - `docs/prd/epic-1-stories-1.3-1.17-tasks.md` - Story 1.8 詳細任務 **聯絡資訊:** - 電話: 02-55700527 - Email: enchuntaiwan@gmail.com - Facebook: (需從原網站取得連結) ## Acceptance Criteria ### AC1 - Contact Page in Payload CMS 在 Payload CMS 中建立 contact-us 頁面,包含: - Hero section: 標題「聯絡我們」 - 表單區塊標題和說明文字 - 聯絡資訊區塊內容 - CTA 區塊內容 ### AC2 - Contact Form Fields 表單包含以下欄位: - **Name** (姓名) - 必填 - **Email** (電子郵件) - 必填,需驗證格式 - **Phone** (電話) - 選填 - **Message** (訊息內容) - 必填,textarea - **Service Interest** (感興趣的服務) - 下拉選單 ### AC3 - Client-Side Validation - 即時欄位驗證 - Email 格式驗證 - 必填欄位檢查 - 錯誤訊息顯示 - Submit 按鈕 loading state ### AC4 - Form Submission Logic - API route: `/api/contact` - Cloudflare Worker 處理表單提交 - Email 發送 (使用 Resend) - Spam protection: - Honeypot field - Rate limiting (每 IP 每小時最多 3 次) - 錯誤處理和重試機制 ### AC5 - Success/Error Display - 成功訊息:「感謝您的留言,我們會盡快回覆您!」 - 錯誤訊息:「發生錯誤,請稍後再試或直接撥打 02-55700527」 - 訊息顯示後表單重置 ### AC6 - Contact Info Display 顯示以下聯絡資訊: - 電話: 02-55700527 (可點擊 tel: 連結) - Email: enchuntaiwan@gmail.com (可點擊 mailto: 連結) - Facebook 連結 (圖示 + 文字) ### AC7 - CTA Section - 醒目的行動呼籲區塊 - 標題和描述文字 - 主要 CTA 按鈕設計 ### AC8 - Visual Fidelity 視覺保真度 ≥ 95% 與 Webflow 原網站相比 ## Tasks / Subtasks ### Task 1.8.1: Create Contact Page in Payload CMS (1h) **Acceptance Criteria:** - [ ] 在 Pages collection 建立 contact-us 頁面 - [ ] Slug: `contact-us` - [ ] Hero section: - Title: "聯絡我們" - Description: 可選的副標題 - [ ] Contact form section: - 表單標題 - 表單說明文字 - [ ] Contact info section: - Phone: 02-55700527 - Email: enchuntaiwan@gmail.com - Facebook link - [ ] CTA section 內容 - [ ] SEO meta tags 配置 **Definition of Done:** - [ ] contact-us 頁面在 Payload admin 可編輯 - [ ] 所有 sections 可編輯 - [ ] Preview 功能正常 --- ### Task 1.8.2: Create contact-us.astro Route (1h) **Acceptance Criteria:** - [ ] 建立 `apps/frontend/src/pages/contact-us.astro` - [ ] 使用 MainLayout (來自 Story 1.4) - [ ] 從 Payload API 載入頁面內容 - [ ] SEO meta tags 動態生成 - [ ] 錯誤處理 (404 或 API 失敗) **Definition of Done:** - [ ] /contact-us 路由正常運作 - [ ] 從 Payload 成功載入內容 - [ ] 錯誤處理正常 --- ### Task 1.8.3: Implement Contact Form Component (2h) **Acceptance Criteria:** - [ ] 建立 `ContactForm.astro` 組件 - [ ] 表單欄位實作: - Name input (text, required) - Email input (email, required) - Phone input (tel, optional) - Message textarea (required) - Service Interest select (dropdown) - [ ] Client-side validation: - HTML5 validation attributes - JavaScript 即時驗證 - 錯誤訊息顯示 - [ ] Submit 按鈕: - Loading state (提交中) - Disabled state (驗證失敗或提交中) - [ ] 成功/錯誤訊息顯示區塊 **Service Interest 下拉選單選項:** - Google 商家關鍵字 - Google Ads - 社群代操 - 論壇行銷 - 網紅行銷 - 形象影片 - 網站設計 - 其他 **Definition of Done:** - [ ] ContactForm 組件完成 - [ ] 所有欄位正常運作 - [ ] 驗證功能正常 - [ ] UI/UX 流暢 --- ### Task 1.8.4: Implement Form Submission Logic (2h) **Acceptance Criteria:** - [ ] 建立 API route `/api/contact` - [ ] 接收 POST 請求: - Body: { name, email, phone, message, serviceInterest } - [ ] Server-side validation: - 檢查必填欄位 - Email 格式驗證 - Honeypot 檢查 (spam detection) - [ ] Rate limiting: - 每個 IP 每小時最多 3 次提交 - [ ] Email 發送 (使用 Resend): - To: enchuntaiwan@gmail.com - Subject: 「聯絡表單: {name}」 - Body: 包含所有表單資料 - [ ] 錯誤處理: - 驗證錯誤 → 400 - Rate limit → 429 - Email 發送失敗 → 500 - [ ] 成功回應 → 200 **Email 格式範例:** ```markdown # 新的聯絡表單提交 **姓名:** {name} **Email:** {email} **電話:** {phone} **感興趣的服務:** {serviceInterest} **訊息內容:** {message} --- 提交時間: {timestamp} IP: {ip} ``` **Definition of Done:** - [ ] API route 正常運作 - [ ] Email 成功發送 - [ ] Spam protection 運作 - [ ] Rate limiting 運作 - [ ] 錯誤處理完善 --- ### Task 1.8.5: Implement Contact Info Display (0.5h) **Acceptance Criteria:** - [ ] 建立 `ContactInfo.astro` 組件 - [ ] Phone 顯示: - 圖示 (電話) - 文字: 02-55700527 - 可點擊 tel:02-55700527 - [ ] Email 顯示: - 圖示 (信封) - 文字: enchuntaiwan@gmail.com - 可點擊 mailto:enchuntaiwan@gmail.com - [ ] Facebook 顯示: - 圖示 (Facebook) - 連結文字: 「恩群數位 Facebook」 **Definition of Done:** - [ ] ContactInfo 組件完成 - [ ] 所有連結可點擊 - [ ] 響應式佈局 --- ### Task 1.8.6: Implement CTA Section (0.5h) **Acceptance Criteria:** - [ ] 使用共用 CTASection 組件 (來自 Story 1.5) - [ ] 標題和描述從 Payload CMS 載入 - [ ] CTA 按鈕設計一致 **Definition of Done:** - [ ] CTA section 正常顯示 - [ ] 與其他頁面設計一致 --- ### Task 1.8.7: Testing and Validation (1h) **Acceptance Criteria:** - [ ] 表單驗證測試: - 必填欄位空白時顯示錯誤 - Email 格式錯誤時顯示錯誤 - 選填欄位空白可正常提交 - [ ] 表單提交測試: - 成功提交顯示成功訊息 - 表單重置 - Email 收到正確內容 - [ ] Spam protection 測試: - Honeypot 填寫被拒絕 - Rate limiting 運作 - [ ] 錯誤處理測試: - API 錯誤顯示錯誤訊息 - 網路錯誤顯示錯誤訊息 - [ ] 視覺保真度測試: - 與 Webflow 原網站對比 - 保真度 ≥ 95% **Definition of Done:** - [ ] 所有測試通過 - [ ] 無阻塞性問題 - [ ] 視覺符合預期 ## Dev Technical Guidance ### File Structure ``` apps/frontend/src/ ├── pages/ │ └── contact-us.astro ← Create this ├── components/ │ └── contact/ │ ├── ContactForm.astro ← Create this │ └── ContactInfo.astro ← Create this ├── styles/ │ └── contact.css ← Create this (optional) apps/backend/src/ ├── routes/ │ └── contact.ts ← Create this (API route) └── email/ └── contact-template.ts ← Create this (email template) ``` ### ContactForm.astro 組件架構 ```typescript // apps/frontend/src/components/contact/ContactForm.astro interface Props { services?: string[] } const { services = defaultServices } = Astro.props // Form state let formState = 'idle' // 'idle' | 'submitting' | 'success' | 'error' let errors = {} // Honeypot field (hidden from users, visible to bots) ``` ### API Route 實作 ```typescript // apps/backend/src/routes/contact.ts import type { APIRoute } from 'astro' import Resend from 'resend' const resend = new Resend(import.meta.env.RESEND_API_KEY) const rateLimiter = new Map() export const POST: APIRoute = async ({ request }) => { const body = await request.json() const ip = request.headers.get('x-forwarded-for') || 'unknown' // Rate limiting // Validation // Honeypot check // Email sending // Response } ``` ### 環境變數 ```bash # .env RESEND_API_KEY=re_xxxxxxxxxxxxx CONTACT_TO_EMAIL=enchuntaiwan@gmail.com CONTACT_FROM_EMAIL=noreply@enchun.tw ``` ### Design Tokens 參考 Webflow 原網站的聯絡頁面設計: - 表單欄位樣式 - 按鈕樣式 - 間距和佈局 - 響應式斷點 ## Dev Notes ### Architecture Patterns - Astro SSR mode for API routes - Resend for email delivery (已選擇的服務) - Honeypot + rate limiting for spam protection - Client-side validation for better UX ### Source Tree Components - `apps/frontend/src/pages/contact-us.astro` - Main contact page - `apps/frontend/src/components/contact/` - Contact-specific components - `apps/backend/src/routes/contact.ts` - Form submission API ### Testing Standards - Manual form validation testing - Email receiving test - Spam protection testing - Visual fidelity comparison (95%+) ### References - [Source: docs/prd/05-epic-stories.md#Story-1.8](docs/prd/05-epic-stories.md) - Story requirements - [Source: docs/prd/epic-1-stories-1.3-1.17-tasks.md#Story-1.8](docs/prd/epic-1-stories-1.3-1.17-tasks.md) - Detailed tasks - [Source: research/www.enchun.tw/contact-us.html](../../research/www.enchun.tw/contact-us.html) - Original Webflow page ### Previous Story Intelligence **From Story 1.4 (Global Layout):** - MainLayout 組件已建立 - Header 和 Footer 可用 - 響應式導航已完成 **From Story 1.5 (Homepage):** - CTASection 組件可重用 - 表單樣式模式可參考 ### Technology Constraints - Astro 4.x SSR mode - Payload CMS 3.x for content - Resend for email delivery - TypeScript strict mode ### Known Issues to Avoid - ⚠️ 不要在 client-side 暴露 API keys - ⚠️ 不要忘記 rate limiting (容易被濫用) - ⚠️ 不要使用同步 email 發送 (會阻塞 response) - ⚠️ 不要忽視 spam protection (會收到大量垃圾訊息) - ⚠️ 不要在錯誤訊息中暴露系統資訊 ### Service Interest Dropdown Options 根據原網站的服務項目,下拉選單應包含: 1. Google 商家關鍵字 2. Google Ads 3. 社群代操 4. 論壇行銷 5. 網紅行銷 6. 形象影片 7. 網站設計 8. 其他 ## Risk Assessment | Risk | Probability | Impact | Mitigation | |------|------------|--------|------------| | Email service downtime | Low | High | Implement fallback logging | | Spam abuse | Medium | Medium | Honeypot + rate limiting + reCAPTCHA (optional) | | Form UX issues | Low | Medium | Thorough testing, clear error messages | | Visual inconsistencies | Low | Low | Use design tokens from Webflow | ## Definition of Done - [ ] contact-us.astro 頁面建立完成 - [ ] ContactForm 組件完成 - [ ] ContactInfo 組件完成 - [ ] API route `/api/contact` 正常運作 - [ ] Email 發送功能正常 - [ ] Spam protection 運作 - [ ] 所有測試通過 - [ ] 視覺保真度 ≥ 95% - [ ] Code follows existing patterns - [ ] No linting errors - [ ] sprint-status.yaml updated to mark story as ready-for-dev ## Dev Agent Record ### Agent Model Used *To be filled by Dev Agent* ### Debug Log References *To be filled by Dev Agent* ### Completion Notes *To be filled by Dev Agent* ### File List *To be filled by Dev Agent* ## Change Log | Date | Action | Author | |------|--------|--------| | 2026-01-31 | Story created with comprehensive context | SM Agent (Bob) |