feat(milestones): persist milestone data server-side via /api/milestones#2307
feat(milestones): persist milestone data server-side via /api/milestones#2307nyxsky404 wants to merge 1 commit into
Conversation
|
@nyxsky404 is attempting to deploy a commit to the PRIYANSHU DOSHI's projects Team on Vercel. A member of the Team first needs to authorize it. |
GSSoC Label Checklist 🏷️@Priyanshu-byte-coder — please apply the appropriate labels before merging: Difficulty (pick one):
Quality (optional):
Validation (required to score):
|
|
The CI failures on this PR (Playwright smoke tests and Playwright visual regression) are pre-existing broken tests on Root causes fixed:
Fixes have been applied to this branch. CI is Green. |
|
This PR has merge conflicts with the current git fetch origin main
git merge origin/main
# resolve conflicts
git push |
MilestonePlanner was storing all user data exclusively in localStorage, meaning milestones were lost whenever a user switched devices, used a different browser, or cleared site storage. Adds a milestones table (Supabase migration), GET/POST routes at /api/milestones, and PATCH/DELETE routes at /api/milestones/[id], following the same auth and validation patterns as the Goals API. MilestonePlanner now fetches from and writes to the API. Increment (+1) and delete use optimistic UI with rollback on network failure so interactions feel instant. The STORAGE_KEY / localStorage helpers are removed entirely. Field names use snake_case in the DB and camelCase in API request bodies to match project conventions. A per-user cap of 20 milestones and DB check constraints mirror the validation in the route handlers. Fixes Umbrella-io#2303
420a899 to
ef1c73b
Compare
Summary
MilestonePlannerwas storing all milestone data exclusively inlocalStorage. This meant milestones were silently lost whenever a user switched devices, used a different browser, opened an incognito window, or cleared browser storage. This PR replaces localStorage with a proper server-side persistence layer that follows the same patterns as the existing Goals feature.Closes #2303
Type of Change
What Changed
Database
supabase/migrations/20260610000000_add_milestones.sql— newmilestonestable withuser_id,title,description,target_value,current_value,unit,target_date,category,created_at. Includescheckconstraints that mirror API validation.API Routes
src/app/api/milestones/route.ts—GET(list user's milestones, capped at 20) andPOST(create with full validation: title sanitisation viastripHtml, integer bounds, per-user limit)src/app/api/milestones/[id]/route.ts—PATCH(updatecurrent_valueonly, clamped totarget_value) andDELETE(user-scoped, no accidental cross-user deletion)Component
src/components/MilestonePlanner.tsx— removedSTORAGE_KEYand alllocalStoragecalls; replaced with API fetch on mount and API calls on create/increment/delete. Increment uses optimistic UI with rollback. Delete uses optimistic removal with reload-on-failure. Addedloadingandsavingstates, and an error display withrole="alert".How to Test
/dashboardand open the Milestone Planner widget.Expected result: All milestones survive across devices, browsers, and storage clears.
Checklist
console.log, debug code, or commented-out blockspnpm run type-check— errors shown are all pre-existing)session?.githubId) on all API routes — unauthenticated requests return 401user_id— no cross-user data access possiblestripHtmlbefore DB insertAdditional Context
API request bodies use camelCase (
targetValue,currentValue) to match JavaScript conventions; the DB schema uses snake_case (target_value,current_value) following the existing project schema style. TheMilestoneinterface in the component was updated to match DB column names directly, eliminating a manual mapping layer.