PublicPersonal Project

Ocean Keep Diving

透過與店家討論網站所需頁面、資訊架構與視覺風格,由我獨立完成資料彙整、路由規劃、UI 設計、網站開發、部署、網域設定、多國語言支援、SEO 優化、以及內容管理系統(CMS)的導入。

網站內容涵蓋潛水課程、教練介紹、價目資訊、活動行程與聯絡方式,並以可維護、可持續擴充為主要設計方向。

線上網址

潛堡潛水 Ocean Keep Diving

技術棧

Next.js, React, Tailwind CSS, DaisyUI, Sanity, next-intl, Docker, Nginx, DigitalOcean, Cloudflare

內容管理系統(CMS)選擇

除了不常變動的固定內容,店家也希望能有寫文章、放文章的空間,而儘管資料結構整理的很好維護,能快速新增或是更新資料,但如果每次更動都需要開發者修改程式重新部署,會增加更多維護成本。

因此決定導入 Headless CMS,與我個人網站使用的 Strapi 不同,這次選擇的是 Sanity,主要是基於成本考量,另一方面也想藉此機會試試看別的系統。

Sanity 可以很簡單的修改 config,然後部署 studio 在他們的網頁上,店家只要在網頁上編輯文件,就可以馬上反應到店家官網。

Sanity 的 API query 會用到他們自家寫的 GROQ(Graph-Relational Object Queries)語法。GROQ 可以直接依照文件類型、欄位條件與排序規則篩選資料,並只回傳頁面實際需要的欄位。

範例:

const POSTS_QUERY = defineQuery(`*[
  _type == "post"
  && defined(slug.current)
]|order(publishedAt desc)[0...24]{
  _id,
  title,
  category,
  slug,
  publishedAt,
  excerpt,
  image
}`);

這段查詢會取得具有有效 slug 的文章,按照發布日期由新到舊排序,限制最多回傳 24 筆資料,並只選取文章列表所需的欄位。

網站架構

網站使用 Next.js 建立,並依照課程、教練、行事曆、文章及其他內容規劃路由。

共用的畫面區塊會拆分為可重複使用的 React 元件,內容則以結構化資料控制。新增相似頁面或調整網站資訊時,可以沿用既有元件與資料格式,避免重複實作相同的版面。

Next.js 也能在路由、Metadata 與伺服器端內容取得方面提供整合,使不同頁面可以根據實際內容產生對應的標題、描述與網址資訊。

多國語言

網站使用 next-intl 實作繁體中文、英文與日文版本,並根據語言建立對應路由。

導覽列、按鈕、頁面文字及 Metadata 等內容皆能依照目前語系顯示,使不同語言版本保持一致的網站結構與使用體驗。

SEO 優化

網站針對搜尋引擎收錄與分享預覽進行以下設定:

  • 各頁面專屬的標題與描述
  • Open Graph Metadata
  • Canonical URL
  • Sitemap
  • Robots 設定
  • 語意化 HTML 結構
  • 多國語言頁面對應
  • 圖片替代文字
  • HTTP 重新導向至 HTTPS

部署與網域設定

網站以 Docker 建立部署環境,部署於 DigitalOcean,並使用 Nginx 作為反向代理伺服器。

Cloudflare 負責 DNS、HTTPS 與流量代理,另外完成裸網域、www 網域與 HTTP/HTTPS 之間的重新導向設定,確保使用者透過不同網址進入時,都會導向正確且安全的網站版本。

專案成果

這個專案從店家的實際需求出發,完整處理內容整理、資訊架構、設計、開發、部署與後續維護方式。

透過可重用元件、結構化資料與 CMS,網站能在維持一致視覺風格的同時,讓內容持續更新與擴充,降低店家未來維護網站的成本。