Side Projects

RoundQ 圈問

RoundQ 圈問

與好友圈深度對話的問答平台。在私密的好友圈中,每一期由發起人設計 3–10 個精心問題,好友一起回答;答案以「人」為中心完整呈現,而不是散落在群組訊息裡。支援 Tiptap 富文本與圖片、按讚留言、歷史回顧、公開圈與範例 Round、中英多語系。

要解決的問題

這個專案的起點是一份每月發給朋友的問卷:問大家最近在忙什麼、有什麼開心或煩惱的事,收到回覆後再手動整理成文件分享出去。群組聊天室雖然即時,但訊息很快被洗掉,事後也很難回顧;問卷則需要人工整理,而且很難同時經營好幾個朋友圈。RoundQ 想把「收集、整理、分享」這段流程自動化,同時保留聊天室沒有的結構與深度。

畫面截圖

  • RoundQ 首頁:左側標語「與好友圈深度對話」,右側為一位朋友的回答卡片,含問題、文字回答、照片與按讚留言數

主要功能

  • 以期為單位的問答

    發起人為好友圈設計一期 3–10 個問題,可以從分類好的問題模板挑選,也能為一期同時指定多個好友圈。每一期都會歸檔,之後隨時可以回頭翻看。

  • 以人為中心的回答呈現

    每位朋友對所有問題的回答被整理成一張完整的卡片,而不是依問題拆散。按讚與留言也是針對這整份回答,讓互動回到「這個人最近過得怎樣」。

  • 富文本與圖片

    回答使用 Tiptap 編輯器,可以圖文混排;圖片在瀏覽器端先壓縮再上傳到 Supabase Storage。

  • 延遲揭曉

    發起人可以選擇立即公開答案,或在達到指定回答人數、到達截止時間、由發起人手動操作時才揭曉,讓每個人先獨立思考再看別人的答案。發起人也能把個別問題設為只有自己看得到。

  • 溫和的即時更新與通知

    有人提交新回答時,頁面只顯示「有新回答,點擊查看」的提示,不會突然改變正在閱讀的內容。站內通知、瀏覽器推播與留言中的 @提及 會把朋友帶回來。

  • 公開圈與範例 Round

    除了私密圈,也支援公開圈與不需登入就能瀏覽的範例 Round,讓第一次來的人先看到實際的樣子。介面提供繁體中文與英文。

技術架構

前端使用 Next.js(App Router)、React 19、TypeScript strict mode 與 Tailwind CSS v4,元件以 shadcn/ui 為基礎,部署在 Vercel。後端選擇 Supabase,一次取得 PostgreSQL、Auth、Realtime 與 Storage,讓一人開發的專案不必自己維護伺服器。伺服器狀態交給 TanStack Query,UI 狀態用 Zustand,寫入操作透過 next-safe-action 包裝的 Server Actions,並以 Zod 驗證輸入。權限規則寫在資料庫的 Row Level Security policy 裡,前端只負責呈現;多語系使用 next-intl,測試則以 Vitest 與 Playwright 分別涵蓋單元與端對端流程。

技術挑戰與取捨

  • 答案隱藏不能只靠前端

    延遲揭曉的重點是答案公開前,其他成員真的拿不到資料。只在前端把答案藏起來,任何人看網路請求就能繞過。最後把規則寫進 responses 資料表的 RLS policy:自己的回答永遠看得到、發起人看得到全部、其他人要等該期揭曉後才查得到。依截止時間揭曉的部分由資料庫內的 pg_cron 每分鐘檢查,揭曉時再由 trigger 產生通知給已回答的成員。

  • 一期問答跨多個好友圈

    早期設計是一期只屬於一個圈子,但同一組問題常常想同時問大學同學和家人。改成多對多之後,新增 round_circles 關聯表,並在每筆回答記錄它來自哪個圈子。RLS 隨之調整為:發起人可以看到所有圈子的回答,一般成員只看得到同圈的回答。這樣一份問卷可以重複使用,不同圈子的回答也不會互相曝光。

  • 成員離開後,回答要不要留下

    這個問題影響資料表設計,所以在動工前先寫成決策文件。考慮過的選項有:保留回答、隨成員離開一起刪除、讓離開的人自己選。刪除會讓其他人的回應失去上下文,也違背「可以回顧」這個核心價值;讓使用者選擇則增加介面與實作的複雜度。最後採用保留回答:離開圈子只移除成員資格,過去的回答仍留在該期裡,其他成員回顧時對話依然完整。

現況

響應式網頁應用,已上線於 roundq.app,支援桌面與手機瀏覽器,介面提供繁體中文與英文。

使用技術

  • Next.js 16
  • React 19
  • Supabase
  • TanStack Query
  • Zustand
  • Tiptap
  • Tailwind v4
  • next-intl

更多Side Projects