Files
website-enchun-mgr/_bmad-output/implementation-artifacts/1-8-contact-page.story.md
pkupuk e9897388dc docs: separate documentation and specs into initial commit
Establish baseline for project documentation including BMAD specs, PRD, and system architecture notes.
2026-02-11 11:49:49 +08:00

12 KiB
Raw Blame History

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 詳細任務

聯絡資訊:

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:
  • 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):
  • 錯誤處理:
    • 驗證錯誤 → 400
    • Rate limit → 429
    • Email 發送失敗 → 500
  • 成功回應 → 200

Email 格式範例:

# 新的聯絡表單提交

**姓名:** {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 顯示:
  • 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 組件架構

// 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)
<input
  type="text"
  name="website_url"
  class="hidden"
  tabindex="-1"
  autocomplete="off"
/>

API Route 實作

// 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<string, { count: number; resetTime: number }>()

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
}

環境變數

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

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)