# 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) |