YI

最初的旅程:一個人,也能啟動一個世界

Taiwan
YI

Dev

軟刪除這件小事,背後的細節卻不小

軟刪除這件小事,背後的細節卻不小 原本只想補一個產品刪除 API。硬刪除直覺又乾脆,但總會有人手滑、客服就會來敲門。最後還是加了 deletedAt 欄位,用軟刪除留個回頭路。 一做下去才發現沒那麼單純:所有產品查詢都要顧到「未刪除」的狀態,沒有 WHERE deletedAt IS NULL 就會漏風。服務層邏輯跟 API 文件也都得跟著調,免得前端看到回傳數量不對又一臉問號。 刪除做完,回頭補分類查詢。前一晚還在想:「分類過濾真的有人用嗎?」如果首頁只放「最近分析的產品」,確實沒什麼意思。乾脆把首頁改成分類區塊,產品頁也補上分類過濾。React 端只是狀態篩選,沒太多問題;後端就麻煩了。 一開始用判斷 categoryId 的單層過濾,寫到一半才想到還有子分類。只好改成遞迴,把子分類的產品一併撈進來,測試也補齊,避免邊界情境漏掉。 今天接前端馬上踩坑:原本只有一層下拉,後端已經支援子分類,前端卻還是平面結構。

By YI

Dev

為體驗與準確性重構一切

圖片輪播的坑,比我想的深得多。昨天把 .gitignore 的怪事整理完,今天回到產品開發,把待辦清單裡的圖片輪播放進度。原本估半小時的小元件,結果一做就發現邊界狀況一堆。 先是圖片 URL 的檢查,避免破圖。寫到載入狀態才真正頭痛——使用者網路慢,圖片還沒載好,輪播就先動,那體驗直接崩。我改成所有圖片載完再開始輪播,空檔用 placeholder 撐住。以為穩了,接著又遇到載入失敗要怎麼處理?最後還是每張都加 onError,統一顯示 fallback 圖。不浪漫,但必要。因為破圖看起來不只像 bug,更像品牌管理失敗。 前端收尾後回到 API。產品分類查詢本來是簡單的 CRUD,結果分頁+子分類一上場,原本的產品資料模型就不夠用了,查詢邏輯整個打結。只好重構模型,補上子分類結構,連產品分析服務的主要功能也一起調整,讓「產品質地描述」的提取跟新架構對齊。這種調整就是牽一髮動全身,漏一角,

By YI

Dev

中文用語統一大作戰:從小細節到底層穩定,這週我修了哪些坑

本來計畫把時間放在核心功能的優化,結果一打開產品分析服務的介面,先被一堆不一致的中文用詞刺了一下。看似微小的「上傳」「提交」「新增」差異,對品牌商用戶的專業感和信任度卻是很實在的扣分。想到我們的客群特別在乎質感,我還是把今天的重心從新功能挪開,展開一場用語清掃。 原本只想改幾個明顯錯誤,一搜 repo 才發現同一概念居然有十幾種搭配方式。最後我從使用情境與用戶習慣出發,整理了一份用語表,將「提交資料」「新增商品」一律統一為「上傳產品」。順手檢查之前的 log,也驚覺開發初期為了快,留下了 test.log、debug.log、temp.log 等臨時檔,甚至沒被 .gitignore 排除。這些東西被 commit 進 repo,真的不行。於是我把怪異的日誌檔案全數加入忽略規則,清乾淨殘留檔案,整個專案視覺與結構都清爽許多。 如果說這天的成果看起來不炫炮,那這週整體就是一場「挖坑與填坑」的連續劇:AI

By YI

Dev

AI 分類越做越複雜,是在挖坑還是填坑?

AI 分類越做越複雜,是在挖坑還是填坑? 這幾天把重心放在兩件事:產品分類的 AI 自動化,以及安全檢查服務的重構。原本以為只是把 API 接上、模型升級一下,結果一路從資料結構、路由、日誌,到架構設計全被牽出來重整。 先談分類。 起手式很直接:把產品名稱與描述丟給模型,取回分類結果後寫進資料庫。實際跑才發現兩個問題 1. 回傳格式不穩:JSON 偶爾多空格或斷行,導致 parse 失敗。我先加上 try-catch,並把原始回應與錯誤完整記錄,至少 debug 不再摸黑。 2. 分類邏輯不合理:現實中同一產品常對應多個類別(如保濕/防曬/抗老化),單一分類會誤導。 因此進行重構: * 將「產品—分類」改為多對多,重整資料庫 schema; * 重新排 API

By YI

從「重構深淵」回到「產品價值」

這週又走進熟悉的重構循環:API 架構、頭像 URL 的 timestamp 快取、副作用處理、訪客帳號暱稱同步,以及 FindSkin 的命名與流程一致性。每個小改動都牽出更大的設計問題,讓人不免自嘲「又在自找麻煩」。但冷靜看,這些牽動其實都指向同一件事:早期設計沒有把未來使用情境想清楚。短期看不痛不癢,長期就是技術債,會拖慢產品節奏。 具體進展: * FindSkin 流程重新梳理,命名與 API/資料表/UX 一致;問卷輸入驗證補強,並在 API 層加上日誌,預防異常輸入。 * 個人化分析的動線重做:由「用戶要自己回到歷史紀錄找結果」改成系統主動引導,看得到、看得懂、看得快。這種體驗上的「短路」比功能多十個更有價值。 最大感受: 我常把重構當成一次解決所有問題的機會,結果每次都把事情做大。工程師的完美主義很好,但要分清楚「

By YI
FindSkin:從命名到體驗,把混亂收回來

Dev

FindSkin:從命名到體驗,把混亂收回來

Ingrelens 這次整理 FindSkin,我不只做功能,而是回到產品要解決什麼:先扎實研究文獻、設計情境題,再用權重公式準確定位膚質類型,最後把結果落到五維雷達圖的可視化呈現。 命名統一為 FindSkin:語意是一切互動的入口 過去「膚質檢測/肌膚分析/問卷調查」並列,容易讓溝通產生分岔,統一命名,等於把概念收攏成一條路,API、資料表、前端組件與 token 邏輯一起對齊,降低學習與維護成本,讓產品後續能長在同一根骨架上。 加上進度條與狀態管理:用可預期感建立信任 FindSkin 設計成 1 分鐘輕量工具,核心價值在「我知道還要多久、接下來會發生什麼」。進度顯示與提交後自動跳結果頁,是把不確定感清掉,讓人更願意完成。前端把標語做成層次分明的堆疊,哪怕是透明度 0.6 與 0.7 的選擇,都是在調整注意力,讓理解更快。 重寫首頁與介紹:

By YI
看不見的細節,為什麼值得?

Dev

看不見的細節,為什麼值得?

今天的開發原本很單純:做一個訪客帳號。實作後卻發現,真正的難題不在「能不能用」,而在「用起來是否一致、可信」。這一整天的折返,讓我更確定:產品的差異,往往來自那些用戶不會主動說出口、卻一直被感受到的細節。 一、身分與名稱的一致性不是錦上添花 一開始我以為 localStorage 放個暱稱就好。等到遇到「訪客是否能轉正」「名稱如何同步」「初始化狀態怎麼顯示」這些情境,才知道「一致性」是一個系統性問題。把名稱同步拉回 AuthProvider,用 isInitialized 管初始化,表面上只是消除 UI 的「閃一下」,本質上是在建立信任:系統不跳針、狀態不自打臉,用戶願意繼續投入注意力。 二、互動設計的邊界:保留動機,拒絕濫用,產品評論的設計,我刻意不讓訪客直接留言,而是用「訪客資訊提示框」引導註冊。這個取捨看似保守,目標卻很清楚:

By YI

Dev

重構永遠不是「只是改一下」的事

今天原本只打算把產品頁改成 client-side component,改善 SSR 時卡卡的效能與 UX。結果一碰到 loading 與 error 處理,才發現 API 根本沒涵蓋這些情境,只好連同整包一起重整。有人會問:「真的有必要動 API?用戶會在意嗎?」我很確定,這種邊角不處理乾淨,之後一定回頭咬人。 另外先前為了避快取加上的 timestamp 參數也拆掉了。看似能解決快取,實際卻讓圖片 URL 每次都不同,反而破壞瀏覽器快取。最後改成在上傳或刪除頭像時主動重置預覽 URL,用戶看到更新更即時、更順。同時也把顏色生成函式修了一下,避免測到那種詭異的橘綠色組合。 下午做產品評分與評論,又卡在「要不要開放訪客留言」。直覺是開放能提升互動,但想到 spam 防治與認證成本,最後先保守,只開放登入會員評論,後續再看數據調整。這類決定難免自我懷疑,但先把基礎守住更務實。 在

By YI

Dev

API 重構後的幾點實話:技術債、產品判斷與下一步

API 重構後的幾點實話:技術債、產品判斷與下一步 這週把 Ingrelens 的幾個老問題一次整起來:API 架構統一、環境變數管理自動化、會員系統與帳號刪除流程重構,還把 HTTP 全面升級到 HTTPS。Dockerfile 重新整理、部署腳本補上該有的保險,過去半年累積的技術債至少清了一大段。 從工程面看,收益很明確。環境變數的自動化腳本雖然寫起來不輕鬆,但部署的穩定度立刻提升,手動改錯的風險幾乎清零;API endpoint 統一後,前端開發少了不少「猜測」與重複修正,後端安全性也更乾淨。這些是值得記上一筆的地方。 但回過頭來,技術債的代價比想像中高。像 endpoint 不一致、URL 寫死在 component、會員系統初期規劃不足,當下看都不急,累積到這週就一次爆掉,時間與心力都被吃掉。結論很直接:之後每次上新功能,都要把「技術債清單」列入例行工作,而不是等到事情變大再處理。

By YI

Dev

Email 驗證、會員系統與那些「看似簡單」的更新紀錄

今天幾乎都在跟會員系統纏鬥。Ingrelens 一開始只是做「註冊、登入」這種基本功能,結果一路長出資料更新、密碼修改、guest 升級成正式會員……每加一個需求,整體邏輯就再複雜一點。 先處理 email 驗證。以前的流程只是寄信、點連結,直到要支援 guest 升級與 email 更改,原本設計就撐不住,尤其 verification metadata 完全不夠用。我改成以一個簡單的 JSON 欄位記錄驗證類型與必要資訊,流程比較有彈性。 接著踩到 profile_data 的坑:它不是每次都能穩定解析成字典,偶爾還會冒出 500。原因是某些地方沒做好 JSON parse 的錯誤處理。最後我強制所有 profile_data 至少回到 dict 型態;parse 失敗就回空字典,

By YI

Dev

把炸彈拆完,才有力氣往前走

游標分頁、環境變數與 API 統一大作戰:把炸彈拆完,才有力氣往前走 有些技術債務不會自己消失,換個環境就原形畢露。這兩天我乾脆把 API URL 的處理邏輯整個抽出來,用環境變數統一管理,再加上 trim,免得前後多了空白符號害人抓狂。順手把散落各處的 console.log 清一輪,才發現 ingredient 的 fetching 端點之前居然不一致,害某些成分 ID 會查不到。笑不太出來,只能重構,把 URL 結構對齊、確認每個 ID 都能讀到資料,附帶補上 error handling。下一次出問題至少能快速定位,而不是盯著螢幕問號連發。 API URL 收拾好後,回頭看最近做的游標分頁,總覺得哪裡卡卡。先前只有單向 next,自己測一測發現使用者一點「上一頁」

By YI

Dev

Dockerfile、環境變數與 API endpoint:一次把坑補齊的週記

這兩天主要在補技術債、梳理架構,過程當然少不了自我懷疑,但也總算把幾個老問題收斂了。 先是 Dockerfile。昨晚就覺得哪裡怪,早上看 deployment log 才確認——前端 CORS 一直叫,後端 API 的 domain whitelist 根本沒吃到。追了半天發現是啟動命令寫法有問題,環境變數沒進去,CORS 就默默回到 localhost。這種低級錯誤不是第一次發生,每次都要再問自己一次:「你到底什麼時候才會記住?」好,這次除了修指令,乾脆把環境變數管理自動化,一個 bash script 負責切換 beta、dev、prod,順手把環境特定的 .env 加進 .gitignore,避免哪一天不小心把敏感資訊推上去。這種看起來小事,但出包就會後悔到爆。 API 這邊也趁機整理。把 api-client 的

By YI